<!DOCTYPE html>
<html lang="en" dir="ltr">

<head prefix="og: http://ogp.me/ns#">
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <title>QUIC&amp;HTTP3相关RFC文档阅读 – ruokeqx&#39;s blog</title>
    


  
  <script defer src="/js/fuse.min.8dfbf8696f107ab8b55732efbb04c5c51576692a4a2cce6effef9f6e92d341a7.js"></script>



<script src="/js/enquire.min.aa37bdcb743826eecdae5c5d177fc7d6552340f1b4378ffaa9c82b2c6111400b.js"></script>

<script defer src="/js/lazysizes.min.498676c34eb225e85357ab0ce19c3c1244f3bd0bf595e5684d1b9d50ea4fbc42.js"></script>

<script defer src="/js/helper/getParents.min.b75dda22e2d1c0e1e0574c7764bb95bec70c0fb0d4d5440339ba68c685d5a661.js"></script>

<script defer src="/js/helper/fadeinout.min.b1a8c6db3f3cc261756044570d21596f0f083625d41433dc9ac02aba5e53777b.js"></script>

<script defer src="/js/helper/closest.min.js"></script>
  
<script>
  "use strict";

  
  
  if (window.NodeList && !NodeList.prototype.forEach) {
    NodeList.prototype.forEach = Array.prototype.forEach;
  }

  
  if (!String.prototype.includes) {
    String.prototype.includes = function (search, start) {
      'use strict';

      if (search instanceof RegExp) {
        throw TypeError('first argument must not be a RegExp');
      }
      if (start === undefined) { start = 0; }
      return this.indexOf(search, start) !== -1;
    };
  }

  
  Document.prototype.append = Element.prototype.append = function append() {
    this.appendChild(_mutation(arguments));
  };
  function _mutation(nodes) {
    if (!nodes.length) {
      throw new Error('DOM Exception 8');
    } else if (nodes.length === 1) {
      return typeof nodes[0] === 'string' ? document.createTextNode(nodes[0]) : nodes[0];
    } else {
      var
      fragment = document.createDocumentFragment(),
      length = nodes.length,
      index = -1,
      node;

      while (++index < length) {
        node = nodes[index];

        fragment.appendChild(typeof node === 'string' ? document.createTextNode(node) : node);
      }

      return fragment;
    }
  }

  
  if (!String.prototype.startsWith) {
    String.prototype.startsWith = function (searchString, position) {
      position = position || 0;
      return this.indexOf(searchString, position) === position;
    };
  }
  


  document.addEventListener('DOMContentLoaded', function () {
    
    var navCollapseBtn = document.querySelector('.navbar__burger');
    navCollapseBtn ? navCollapseBtn.addEventListener('click', function (e) {
      var navCollapse = document.querySelector('.navbarm__collapse');

      if (navCollapse) {
        var dataOpen = navCollapse.getAttribute('data-open');

        if (dataOpen === 'true') {
          navCollapse.setAttribute('data-open', 'false');
          navCollapse.style.maxHeight = 0;
          navCollapseBtn.classList.remove('is-active');
        } else {
          navCollapse.setAttribute('data-open', 'true');
          navCollapse.style.maxHeight = navCollapse.scrollHeight + "px";
          navCollapseBtn.classList.add('is-active');
        }
      }
    }) : null;
    


    
    var tables = document.querySelectorAll('.single__contents > table');
    for (let i = 0; i < tables.length; i++) {
      var table = tables[i];
      var wrapper = document.createElement('div');
      wrapper.className = 'table-wrapper';
      table.parentElement.replaceChild(wrapper, table);
      wrapper.appendChild(table);
    }
    


    
    var footNoteRefs = document.querySelectorAll('.footnote-ref');
    var footNoteBackRefs = document.querySelectorAll('.footnote-backref');

    footNoteRefs ? 
    footNoteRefs.forEach(function(elem, idx) {
      elem.onmouseenter = function () {
        if (navbar.classList.contains('scrolling')) {
          navbar.classList.remove('scrolling');
        }
      }

      elem.onmouseleave = function () {
        if (!navbar.classList.contains('scrolling')) {
          setTimeout(function () {
            navbar.classList.add('scrolling');
          }, 100);
        }
      }

      elem.onclick = function () {
        if (!navbar.classList.contains('scrolling')) {
          navbar.classList.remove('navbar--show');
          navbar.classList.remove('navbar--hide');
          navbar.classList.add('navbar--hide');
        }
      }
    }) : null;

    footNoteBackRefs ? 
    footNoteBackRefs.forEach(function(elem, idx) {
      elem.onmouseenter = function () {
        if (navbar.classList.contains('scrolling')) {
          navbar.classList.remove('scrolling');
        }
      }

      elem.onmouseleave = function () {
        if (!navbar.classList.contains('scrolling')) {
          setTimeout(function() {
            navbar.classList.add('scrolling');
          }, 100);
        }
      }

      elem.onclick = function () {
        if (!navbar.classList.contains('scrolling')) {
          navbar.classList.remove('navbar--show');
          navbar.classList.remove('navbar--hide');
          navbar.classList.add('navbar--hide');
        }
      }
    }) : null;
    


    
    var summaryContainer = document.querySelector('.summary__container');
    var searchResult = document.querySelector('.search-result');
    var searchResultCloseBtn = document.querySelector('.search-result__close');
    searchResultCloseBtn ? searchResultCloseBtn.addEventListener('click', function (e) {
      searchResult.setAttribute('data-display', 'none');
      summaryContainer.setAttribute('data-display', 'block');
    }) : null;
    


    
    document.querySelectorAll('.tab') ? 
    document.querySelectorAll('.tab').forEach(function(elem, idx) {
      var containerId = elem.getAttribute('id');
      var containerElem = elem;
      var tabLinks = elem.querySelectorAll('.tab__link');
      var tabContents = elem.querySelectorAll('.tab__content');
      var ids = [];

      tabLinks && tabLinks.length > 0 ?
      tabLinks.forEach(function(link, index, self) {
        link.onclick = function(e) {
          for (var i = 0; i < self.length; i++) {
            if (index === parseInt(i, 10)) {
              if (!self[i].classList.contains('active')) {
                self[i].classList.add('active');
                tabContents[i].style.display = 'block';
              }
            } else {
              self[i].classList.remove('active');
              tabContents[i].style.display = 'none';
            }
          }
        }
      }) : null;
    }) : null;
    


    
    document.querySelectorAll('.codetab') ? 
    document.querySelectorAll('.codetab').forEach(function(elem, idx) {
      var containerId = elem.getAttribute('id');
      var containerElem = elem;
      var codetabLinks = elem.querySelectorAll('.codetab__link');
      var codetabContents = elem.querySelectorAll('.codetab__content');
      var ids = [];

      codetabLinks && codetabLinks.length > 0 ?
      codetabLinks.forEach(function(link, index, self) {
        link.onclick = function(e) {
          for (var i = 0; i < self.length; i++) {
            if (index === parseInt(i, 10)) {
              if (!self[i].classList.contains('active')) {
                self[i].classList.add('active');
                codetabContents[i].style.display = 'block';
              }
            } else {
              self[i].classList.remove('active');
              codetabContents[i].style.display = 'none';
            }
          }
        }
      }) : null;
    }) : null;
    


    
    var gttBtn = document.getElementById("gtt");
    gttBtn.style.display = "none";
    gttBtn.addEventListener('click', function () {
      if (window.document.documentMode) {
        document.documentElement.scrollTop = 0;
      } else {
        scrollToTop(250);
      }
    });

    function scrollToTop(scrollDuration) {
      var scrollStep = -window.scrollY / (scrollDuration / 15);
      var scrollInterval = setInterval(function () {
        if (window.scrollY != 0) {
          window.scrollBy(0, scrollStep);
        }
        else clearInterval(scrollInterval);
      }, 15);
    }

    var scrollFunction = function () {
      if (document.body.scrollTop > 250 || document.documentElement.scrollTop > 250) {
        gttBtn.style.display = "block";
      } else {
        gttBtn.style.display = "none";
      }
    }
    


    
    var expandBtn = document.querySelectorAll('.expand__button');

    for (let i = 0; i < expandBtn.length; i++) {
      expandBtn[i].addEventListener("click", function () {
        var content = this.nextElementSibling;
        if (content.style.maxHeight) {
          content.style.maxHeight = null;
          this.querySelector('svg').classList.add('expand-icon__right');
          this.querySelector('svg').classList.remove('expand-icon__down');
        } else {
          content.style.maxHeight = content.scrollHeight + "px";
          this.querySelector('svg').classList.remove('expand-icon__right');
          this.querySelector('svg').classList.add('expand-icon__down');
        }
      });
    }
    


    
    var lastScrollTop = window.pageYOffset || document.documentElement.scrollTop;
    var tocElem = document.querySelector('.toc');
    var tableOfContentsElem = tocElem ? tocElem.querySelector('#TableOfContents') : null;
    var toggleTocElem = document.getElementById('toggle-toc');
    var singleContentsElem = document.querySelector('.single__contents');
    var navbar = document.querySelector('.navbar');
    var tocFlexbox = document.querySelector('.toc__flexbox');
    var tocFlexboxOuter = document.querySelector('.toc__flexbox--outer');
    var expandContents = document.querySelectorAll('.expand__content');
    var boxContents = document.querySelectorAll('.box');
    var notAllowedTitleIds = null;

    
    var tocFolding = JSON.parse("true");
    
    var tocLevels = JSON.parse("[\"h2\",\"h3\",\"h4\",\"h5\"]");
    
    if (tocLevels) {
      tocLevels = tocLevels.toString();
    } else {
      tocLevels = "h1, h2, h3, h4, h5, h6";
    }

    
    singleContentsElem && singleContentsElem.querySelectorAll(".tab") ?
    singleContentsElem.querySelectorAll(".tab").forEach(function (elem) {
      elem.querySelectorAll(tocLevels).forEach(function (element) {
        notAllowedTitleIds = Array.isArray(notAllowedTitleIds) ?
          notAllowedTitleIds.concat(element.getAttribute('id')) :
          [element.getAttribute('id')];
      });
    }) : null;

    
    expandContents ? expandContents.forEach(function(elem) {
      elem.querySelectorAll(tocLevels).forEach(function (element) {
        notAllowedTitleIds = Array.isArray(notAllowedTitleIds) ?
          notAllowedTitleIds.concat(element.getAttribute('id')) :
          [element.getAttribute('id')];
      });
    }) : null;

    
    boxContents ? boxContents.forEach(function(elem) {
      elem.querySelectorAll(tocLevels).forEach(function (element) {
        notAllowedTitleIds = Array.isArray(notAllowedTitleIds) ?
          notAllowedTitleIds.concat(element.getAttribute('id')) :
          [element.getAttribute('id')];
      });
    }) : null;

    
    window.onscroll = function () {
      scrollFunction();
      
      var st = window.pageYOffset || document.documentElement.scrollTop;
      if (st > lastScrollTop) { 
        if (st < 250) {
          gttBtn.style.display = "none";
        } else {
          gttBtn.style.display = "block";
        }

        if (st < 45) {
          return null;
        }

        if (navbar.classList.contains('scrolling')) {
          if (!navbar.classList.contains('navbar--hide')) {
            navbar.classList.add('navbar--hide');
          } else if (navbar.classList.contains('navbar--show')) {
            navbar.classList.remove('navbar--show');
          }
        }

        if (singleContentsElem) {
          if (singleContentsElem.querySelectorAll(tocLevels).length > 0) {
            singleContentsElem.querySelectorAll(tocLevels).forEach(function (elem) {
              if (toggleTocElem && !toggleTocElem.checked) {
                return null;
              }

              if (notAllowedTitleIds && notAllowedTitleIds.includes(elem.getAttribute('id'))) {
                return null;
              }
              
              if (document.documentElement.scrollTop >= elem.offsetTop) {
                if (tableOfContentsElem) {
                  var id = elem.getAttribute('id');
                  tocElem.querySelectorAll('a').forEach(function (elem) {
                    elem.classList.remove('active');
                  });
                  tocElem.querySelector('a[href="#' + id + '"]') ?
                    tocElem.querySelector('a[href="#' + id + '"]').classList.add('active') : null;

                  if (false === tocFolding) {
                    
                  } else {
                    tableOfContentsElem.querySelectorAll('ul') ?
                      tableOfContentsElem.querySelectorAll('ul').forEach(function (rootUl) {
                        rootUl.querySelectorAll('li').forEach(function (liElem) {
                          liElem.querySelectorAll('ul').forEach(function (ulElem) {
                            ulElem.style.display = 'none';
                          });
                        });
                      }) : null;
                  }

                  var curElem = tableOfContentsElem.querySelector("[href='#" + id + "']");
                  if (curElem && curElem.nextElementSibling) {
                    curElem.nextElementSibling.style.display = 'block';
                  }
                  getParents(curElem, 'ul') ?
                    getParents(curElem, 'ul').forEach(function (elem) {
                      elem.style.display = 'block';
                    }) : null;
                }
              }
            });
          } else {
            if (tocFlexbox) {
              tocFlexbox.setAttribute('data-position', '');
              if (!tocFlexbox.classList.contains('hide')) {
                tocFlexbox.classList.add('hide');
              }
            }
            if (tocFlexboxOuter) {
              tocFlexboxOuter.setAttribute('data-position', '');
              if (!tocFlexboxOuter.classList.contains('hide')) {
                tocFlexboxOuter.classList.add('hide');
              }
            }
          }
        }
      } else { 
        if (st < 250) {
          gttBtn.style.display = "none";
        }

        if (navbar.classList.contains('scrolling')) {
          if (navbar.classList.contains('navbar--hide')) {
            navbar.classList.remove('navbar--hide');
          } else if (!navbar.classList.contains('navbar--show')) {
            navbar.classList.add('navbar--show');
          }
        }

        if (singleContentsElem) {
          if (singleContentsElem.querySelectorAll(tocLevels).length > 0) {
            singleContentsElem.querySelectorAll(tocLevels).forEach(function (elem) {
              if (toggleTocElem && !toggleTocElem.checked) {
                return null;
              }
              
              if (notAllowedTitleIds && notAllowedTitleIds.includes(elem.getAttribute('id'))) {
                return null;
              }

              if (document.documentElement.scrollTop >= elem.offsetTop) {
                if (tableOfContentsElem) {
                  var id = elem.getAttribute('id');
                  tocElem.querySelectorAll('a').forEach(function (elem) {
                    elem.classList.remove('active');
                  });
                  tocElem.querySelector('a[href="#' + id + '"]') ?
                    tocElem.querySelector('a[href="#' + id + '"]').classList.add('active') : null;

                  if (false === tocFolding) {
                    
                  } else {
                    tableOfContentsElem.querySelectorAll('ul') ?
                      tableOfContentsElem.querySelectorAll('ul').forEach(function (rootUl) {
                        rootUl.querySelectorAll('li').forEach(function (liElem) {
                          liElem.querySelectorAll('ul').forEach(function (ulElem) {
                            ulElem.style.display = 'none';
                          });
                        });
                      }) : null;
                  }

                  var curElem = tableOfContentsElem.querySelector("[href='#" + id + "']");
                  if (curElem && curElem.nextElementSibling) {
                    curElem.nextElementSibling.style.display = 'block';
                  }
                  getParents(curElem, 'ul') ?
                    getParents(curElem, 'ul').forEach(function (elem) {
                      elem.style.display = 'block';
                    }) : null;
                }
              }
            });
          } else {
            if (tocFlexbox && !tocFlexbox.classList.contains('hide')) {
              tocFlexbox.classList.add('hide');
            }
            if (tocFlexboxOuter && !tocFlexboxOuter.classList.contains('hide')) {
              tocFlexboxOuter.classList.add('hide');
            }
          }
          
        }

        if (tableOfContentsElem && document.documentElement.scrollTop < 250) {
          if (false === tocFolding) {

          } else {
            tableOfContentsElem.querySelector('ul') ?
              tableOfContentsElem.querySelector('ul').querySelectorAll('li').forEach(function (liElem) {
                liElem.querySelectorAll('ul').forEach(function (ulElem) {
                  ulElem.style.display = 'none';
                });
              }) : null;
          }
        }
      }
      lastScrollTop = st <= 0 ? 0 : st;
    };
  


  
    var localTheme = localStorage.getItem('theme');
    var rootEleme = document.getElementById('root');
    var selectThemeElem = document.querySelectorAll('.select-theme');
    var selectThemeItemElem = document.querySelectorAll('.select-theme__item');
    
    
    var skinDarkCode = JSON.parse("\"dark\"");
    
    var skinLightCode = JSON.parse("\"light\"");
    
    var skinHackerCode = JSON.parse("\"hacker\"");
    
    var skinSolarizedCode = JSON.parse("\"solarized\"");
    
    var skinKimbieCode = JSON.parse("\"kimbie\"");

    var setMetaColor = function(themeColor) {
      var metaMsapplicationTileColor = document.getElementsByName('msapplication-TileColor')[0];
      var metaThemeColor = document.getElementsByName('theme-color')[0];
      var metaMsapplicationNavbuttonColor = document.getElementsByName('msapplication-navbutton-color')[0];
      var metaAppleMobileWebAappStatusBarStyle = document.getElementsByName('apple-mobile-web-app-status-bar-style')[0];

      if (themeColor.includes('dark')) {
        metaMsapplicationTileColor.setAttribute('content', '#fcfcfa');
        metaThemeColor.setAttribute('content', '#403E41');
        metaMsapplicationNavbuttonColor.setAttribute('content', '#403E41');
        metaAppleMobileWebAappStatusBarStyle.setAttribute('content', '#403E41');
      } else if (themeColor.includes('light')) {
        metaMsapplicationTileColor.setAttribute('content', '#555');
        metaThemeColor.setAttribute('content', '#eee');
        metaMsapplicationNavbuttonColor.setAttribute('content', '#eee');
        metaAppleMobileWebAappStatusBarStyle.setAttribute('content', '#eee');
      } else if (themeColor.includes('hacker')) {
        metaMsapplicationTileColor.setAttribute('content', '#e3cd26');
        metaThemeColor.setAttribute('content', '#252526');
        metaMsapplicationNavbuttonColor.setAttribute('content', '#252526');
        metaAppleMobileWebAappStatusBarStyle.setAttribute('content', '#252526');
      } else if (themeColor.includes('solarized')) {
        metaMsapplicationTileColor.setAttribute('content', '#d3af86');
        metaThemeColor.setAttribute('content', '#51412c');
        metaMsapplicationNavbuttonColor.setAttribute('content', '#51412c');
        metaAppleMobileWebAappStatusBarStyle.setAttribute('content', '#51412c');
      } else if (themeColor.includes('kimbie')) {
        metaMsapplicationTileColor.setAttribute('content', '#586e75');
        metaThemeColor.setAttribute('content', '#eee8d5');
        metaMsapplicationNavbuttonColor.setAttribute('content', '#eee8d5');
        metaAppleMobileWebAappStatusBarStyle.setAttribute('content', '#eee8d5');
      }
    }

    var parseSkinCode = function(themeText) {
      if (themeText === skinDarkCode) {
        return 'dark';
      } else if (themeText === skinLightCode) {
        return 'light';
      } else if (themeText === skinHackerCode) {
        return 'hacker';
      } else if (themeText === skinSolarizedCode) {
        return 'solarized';
      } else if (themeText === skinKimbieCode) {
        return 'kimbie';
      }
    }
    
    if (localTheme) {
      selectThemeItemElem ? 
      selectThemeItemElem.forEach(function (elem) {
        if (elem.text.trim() === localTheme) {
          elem.classList.add('is-active');
        } else {
          elem.classList.remove('is-active');
        }
      }) : null;

      setMetaColor(localTheme);
    } else {
      setMetaColor(rootEleme.className);
    }

    selectThemeItemElem ? 
    selectThemeItemElem.forEach(function (v, i) {
      v.addEventListener('click', function (e) {
        var selectedThemeVariant = parseSkinCode(e.target.text.trim());
        localStorage.setItem('theme', selectedThemeVariant);
        setMetaColor(selectedThemeVariant);

        rootEleme.removeAttribute('class');
        rootEleme.classList.add('theme__' + selectedThemeVariant);
        selectThemeElem.forEach(function(rootElem) {
          rootElem.querySelectorAll('a').forEach(function (elem) {
            if (elem.classList) {
              if (elem.text.trim() === selectedThemeVariant) {
                if (!elem.classList.contains('is-active')) {
                  elem.classList.add('is-active');
                }
              } else {
                if (elem.classList.contains('is-active')) {
                  elem.classList.remove('is-active');
                }
              }
            }
          });
        });

        if (window.mermaid) {
          if (selectedThemeVariant === "dark" || selectedThemeVariant === "hacker") {
            mermaid.initialize({ theme: 'dark' });
            location.reload();
          } else {
            mermaid.initialize({ theme: 'default' });
            location.reload();
          }
        }

        var utterances = document.getElementById('utterances');
        if (utterances) {
          utterances.querySelector('iframe').contentWindow.postMessage({
            type: 'set-theme',
            theme: selectedThemeVariant === "dark" || selectedThemeVariant === "hacker" ? 'photon-dark' : selectedThemeVariant === 'kimbie' ? 'github-dark-orange' : 'github-light',
          }, 'https://utteranc.es');
        }

        var twitterCards = document.querySelectorAll('.twitter-timeline');
        if (twitterCards) {
          window.postMessage({
            type: 'set-twitter-theme',
            theme: selectedThemeVariant === 'light' || selectedThemeVariant === 'solarized' ? 'light' : 'dark',
          });
        }
      });
    }) : null;
  


  
    
    var baseurl = JSON.parse("\"https://ruokeqx.gitee.io\"");
    
    var permalink = JSON.parse("\"https://ruokeqx.gitee.io/posts/quichttp3_related_rfc/\"");
    
    var langprefix = JSON.parse("\"\"");
    var searchResults = null;
    var searchMenu = null;
    var searchText = null;
    
    
    var enableSearch = JSON.parse("true");
    
    var searchDistance = JSON.parse("100");
    
    var searchThreshold = JSON.parse("0.4");
    
    var searchContent = JSON.parse("true");
    
    var enableSearchHighlight = JSON.parse("true");
    
    var searchResultPosition = JSON.parse("\"main\"");
    
    var sectionType = JSON.parse("\"posts\"");
    
    var kind = JSON.parse("\"page\"");
    
    var fuse = null;

    if (enableSearch) {
      (function initFuse() {
        var xhr = new XMLHttpRequest();
        if (sectionType === "publication" && kind !== "page") {
          xhr.open('GET', permalink + "index.json");
        } else {
          xhr.open('GET', baseurl + langprefix + "/index.json");
        }
        
        xhr.setRequestHeader('Content-Type', 'application/json; charset=utf-8');
        xhr.onload = function () {
          if (xhr.status === 200) {
            fuse = new Fuse(JSON.parse(xhr.response.toString('utf-8')), {
              keys: sectionType.includes('publication') ? ['title', 'abstract'] : 
                searchContent ? ['title', 'description', 'content'] : ['title', 'description'],
              includeMatches: enableSearchHighlight,
              shouldSort: true, 
              threshold: searchThreshold ? searchThreshold : 0.4, 
              location: 0, 
              distance: searchDistance ? searchDistance : 100, 
              maxPatternLength: 32,
              minMatchCharLength: 1,
              isCaseSensitive: false, 
              findAllMatches: false, 
              useExtendedSearch: false, 
            });
            window.fuse = fuse;
          }
          else {
            console.error('[' + xhr.status + ']Error:', xhr.statusText);
          }
        };
        xhr.send();
      })();
    }

    function makeLi(ulElem, obj) {
      var li = document.createElement('li');
      li.className = 'search-result__item';
      
      var a = document.createElement('a');
      a.innerHTML = obj.item.title;
      a.setAttribute('class', 'search-result__item--title');
      a.setAttribute('href', obj.item.uri);

      var descDiv = document.createElement('div');
      descDiv.setAttribute('class', 'search-result__item--desc');
      if (obj.item.description) {
        descDiv.innerHTML = obj.item.description;
      } else if (obj.item.content) {
        descDiv.innerHTML = obj.item.content.substring(0, 225);
      }
      
      li.appendChild(a);
      li.appendChild(descDiv);
      ulElem.appendChild(li);
    }

    function makeHighlightLi(ulElem, obj) {
      var li = document.createElement('li');
      li.className = 'search-result__item';
      var descDiv = null;

      var a = document.createElement('a');
      a.innerHTML = obj.item.title;
      a.setAttribute('class', 'search-result__item--title');
      a.setAttribute('href', obj.item.uri);

      if (obj.matches && obj.matches.length) {
        for (var i = 0; i < obj.matches.length; i++) {
          if ('title' === obj.matches[i].key) {
            a = document.createElement('a');
            a.innerHTML = generateHighlightedText(obj.matches[i].value, obj.matches[i].indices);
            a.setAttribute('class', 'search-result__item--title');
            a.setAttribute('href', obj.item.uri);
          }
          
          if ('description' === obj.matches[i].key) {
            descDiv = document.createElement('div');
            descDiv.setAttribute('class', 'search-result__item--desc');
            descDiv.innerHTML = generateHighlightedText(obj.item.description, obj.matches[i].indices);
          } else if ('content' === obj.matches[i].key) {
            if (!descDiv) {
              descDiv = document.createElement('div');
              descDiv.setAttribute('class', 'search-result__item--desc');
              descDiv.innerHTML = generateHighlightedText(obj.item.content.substring(0, 150), obj.matches[i].indices);
            }
          } else {
            if (obj.item.description) {
              descDiv = document.createElement('div');
              descDiv.setAttribute('class', 'search-result__item--desc');
              descDiv.innerHTML = obj.item.description;
            } else {
              descDiv = document.createElement('div');
              descDiv.setAttribute('class', 'search-result__item--desc');
              descDiv.innerHTML = obj.item.content.substring(0, 150);
            }
          }
        }

        li.appendChild(a);
        if (descDiv) {
          li.appendChild(descDiv);
        }
        if (li) {
          ulElem.appendChild(li);
        }
      }
    }

    function renderSearchResultsSide(searchText, results) {
      searchResults = document.getElementById('search-results');
      searchMenu = document.getElementById('search-menu');
      searchResults.setAttribute('class', 'dropdown is-active');
      
      var ul = document.createElement('ul');
      ul.setAttribute('class', 'dropdown-content search-content');

      if (results.length) {
        results.forEach(function (result) {
          var li = document.createElement('li');
          var a = document.createElement('a');
          a.setAttribute('href', result.uri);
          a.setAttribute('class', 'dropdown-item');
          a.appendChild(li);

          var titleDiv = document.createElement('div');
          titleDiv.innerHTML = result.title;
          titleDiv.setAttribute('class', 'menu-item__title');

          var descDiv = document.createElement('div');
          descDiv.setAttribute('class', 'menu-item__desc');
          if (result.description) {
            descDiv.innerHTML = result.description;
          } else if (result.content) {
            descDiv.innerHTML = result.content.substring(0, 150);
          }

          li.appendChild(titleDiv);
          li.appendChild(descDiv);
          ul.appendChild(a);
        });
      } else {
        var li = document.createElement('li');
        li.setAttribute('class', 'dropdown-item');
        li.innerText = 'No results found';
        ul.appendChild(li);
      }

      while (searchMenu.hasChildNodes()) {
        searchMenu.removeChild(
          searchMenu.lastChild
        );
      }
      
      searchMenu.appendChild(ul);
    }

    function renderSearchHighlightResultsSide(searchText, results) {
      searchResults = document.getElementById('search-results');
      searchMenu = document.getElementById('search-menu');
      searchResults.setAttribute('class', 'dropdown is-active');

      var ul = document.createElement('ul');
      ul.setAttribute('class', 'dropdown-content search-content');

      if (results.length) {
        results.forEach(function (result) {
          var li = document.createElement('li');
          var a = document.createElement('a');
          var descDiv = null;

          a.setAttribute('href', result.item.uri);
          a.setAttribute('class', 'dropdown-item');
          a.appendChild(li);

          var titleDiv = document.createElement('div');
          titleDiv.innerHTML = result.item.title;
          titleDiv.setAttribute('class', 'menu-item__title');
          
          if (result.matches && result.matches.length) {
            for (var i = 0; i < result.matches.length; i++) {
              if ('title' === result.matches[i].key) {
                titleDiv.innerHTML = generateHighlightedText(result.matches[i].value, result.matches[i].indices);
              }

              if ('description' === result.matches[i].key) {
                descDiv = document.createElement('div');
                descDiv.setAttribute('class', 'menu-item__desc');
                descDiv.innerHTML = generateHighlightedText(result.item.description, result.matches[i].indices);
              } else if ('content' === result.matches[i].key) {
                if (!descDiv) {
                  descDiv = document.createElement('div');
                  descDiv.setAttribute('class', 'menu-item__desc');
                  descDiv.innerHTML = generateHighlightedText(result.item.content.substring(0, 150), result.matches[i].indices);
                }
              } else {
                if (result.item.description) {
                  descDiv = document.createElement('div');
                  descDiv.setAttribute('class', 'menu-item__desc');
                  descDiv.innerHTML = result.item.description;
                } else {
                  descDiv = document.createElement('div');
                  descDiv.setAttribute('class', 'menu-item__desc');
                  descDiv.innerHTML = result.item.content.substring(0, 150);
                }
              }
            }
            
            li.appendChild(titleDiv);
            if (descDiv) {
              li.appendChild(descDiv);
            }
            ul.appendChild(a);
          }
        });
      } else {
        var li = document.createElement('li');
        li.setAttribute('class', 'dropdown-item');
        li.innerText = 'No results found';
        ul.appendChild(li);
      }

      while (searchMenu.hasChildNodes()) {
        searchMenu.removeChild(
          searchMenu.lastChild
        );
      }
      searchMenu.appendChild(ul);
    }

    function renderSearchResultsMobile(searchText, results) {
      searchResults = document.getElementById('search-mobile-results');

      var content = document.createElement('div');
      content.setAttribute('class', 'mobile-search__content');

      if (results.length > 0) {
        results.forEach(function (result) {
          var item = document.createElement('a');
          item.setAttribute('href', result.uri);
          item.innerHTML = '<div class="mobile-search__item"><div class="mobile-search__item--title">📄 ' + result.title + '</div><div class="mobile-search__item--desc">' + (result.description ? result.description : result.content) + '</div></div>';
          content.appendChild(item);
        });
      } else {
        var item = document.createElement('span');
        content.appendChild(item);
      }

      let wrap = document.getElementById('search-mobile-results');
      while (wrap.firstChild) {
        wrap.removeChild(wrap.firstChild)
      }
      searchResults.appendChild(content);      
    }

    function renderSearchHighlightResultsMobile(searchText, results) {
      searchResults = document.getElementById('search-mobile-results');

      var ul = document.createElement('div');
      ul.setAttribute('class', 'mobile-search__content');

      if (results.length) {
        results.forEach(function (result) {
          var li = document.createElement('li');
          var a = document.createElement('a');
          var descDiv = null;

          a.setAttribute('href', result.item.uri);
          a.appendChild(li);
          li.setAttribute('class', 'mobile-search__item');

          var titleDiv = document.createElement('div');
          titleDiv.innerHTML = result.item.title;
          titleDiv.setAttribute('class', 'mobile-search__item--title');
          
          if (result.matches && result.matches.length) {
            for (var i = 0; i < result.matches.length; i++) {
              if ('title' === result.matches[i].key) {
                titleDiv.innerHTML = generateHighlightedText(result.matches[i].value, result.matches[i].indices);
              }

              if ('description' === result.matches[i].key) {
                descDiv = document.createElement('div');
                descDiv.setAttribute('class', 'mobile-search__item--desc');
                descDiv.innerHTML = generateHighlightedText(result.item.description, result.matches[i].indices);
              } else if ('content' === result.matches[i].key) {
                if (!descDiv) {
                  descDiv = document.createElement('div');
                  descDiv.setAttribute('class', 'mobile-search__item--desc');
                  descDiv.innerHTML = generateHighlightedText(result.item.content.substring(0, 150), result.matches[i].indices);
                }
              } else {
                if (result.item.description) {
                  descDiv = document.createElement('div');
                  descDiv.setAttribute('class', 'mobile-search__item--desc');
                  descDiv.innerHTML = result.item.description;
                } else {
                  descDiv = document.createElement('div');
                  descDiv.setAttribute('class', 'mobile-search__item--desc');
                  descDiv.innerHTML = result.item.content.substring(0, 150);
                }
              }
            }
            
            li.appendChild(titleDiv);
            if (descDiv) {
              li.appendChild(descDiv);
            }
            ul.appendChild(a);
          }
        });
      } else {
        var item = document.createElement('span');
        ul.appendChild(item);
      }

      let wrap = document.getElementById('search-mobile-results');
      while (wrap.firstChild) {
        wrap.removeChild(wrap.firstChild)
      }
      searchResults.appendChild(ul);
    }

    function generateHighlightedText(text, regions) {
      if (!regions) {
        return text;
      }

      var content = '', nextUnhighlightedRegionStartingIndex = 0;

      regions.forEach(function(region) {
        if (region[0] === region[1]) {
          return null;
        }
        
        content += '' +
          text.substring(nextUnhighlightedRegionStartingIndex, region[0]) +
          '<span class="search__highlight">' +
            text.substring(region[0], region[1] + 1) +
          '</span>' +
        '';
        nextUnhighlightedRegionStartingIndex = region[1] + 1;
      });

      content += text.substring(nextUnhighlightedRegionStartingIndex);

      return content;
    };

    var searchElem = document.getElementById('search');
    var searchMobile = document.getElementById('search-mobile');
    var searchResultsContainer = document.getElementById('search-results');

    searchElem ?
    searchElem.addEventListener('input', function(e) {
      if (!e.target.value | window.innerWidth < 770) {
        searchResultsContainer ? searchResultsContainer.setAttribute('class', 'dropdown') : null;
        searchResult ? searchResult.setAttribute('data-display', 'none') : null;
        summaryContainer ? summaryContainer.setAttribute('data-display', 'block') : null;
        return null;
      }

      searchText = e.target.value;
      var results = fuse.search(e.target.value);
      
      if (searchResultPosition === "main") {
        if (enableSearchHighlight) {
          renderSearchHighlightResultsMain(searchText, results);
        } else {
          renderSearchResultsMain(searchText, results);
        }
      } else {
        if (enableSearchHighlight) {
          renderSearchHighlightResultsSide(searchText, results);
        } else {
          renderSearchResultsSide(searchText, results);
        }
        
        var dropdownItems = searchResultsContainer.querySelectorAll('.dropdown-item');
        dropdownItems ? dropdownItems.forEach(function(item) {
          item.addEventListener('mousedown', function(e) {
            e.target.click();
          });
        }) : null;
      }
    }) : null;

    searchElem ? 
    searchElem.addEventListener('blur', function() {
      if (window.innerWidth < 770) {
        return null;
      }
      searchResultsContainer ? searchResultsContainer.setAttribute('class', 'dropdown') : null;
    }) : null;

    searchElem ? 
    searchElem.addEventListener('click', function(e) {
      if (window.innerWidth < 770) {
        return null;
      }
      if (!e.target.value) {
        searchResultsContainer ? searchResultsContainer.setAttribute('class', 'dropdown') : null;
        return null;
      }

      searchText = e.target.value;
      var results = fuse.search(e.target.value);

      if (searchResultPosition === "main") {
        if (enableSearchHighlight) {
          renderSearchHighlightResultsMain(searchText, results);
        } else {
          renderSearchResultsMain(searchText, results);
        }
      } else{
        if (enableSearchHighlight) {
          renderSearchHighlightResultsSide(searchText, results);
        } else {
          renderSearchResultsSide(searchText, results);
        }

        var dropdownItems = searchResultsContainer.querySelectorAll('.dropdown-item');
        dropdownItems ? dropdownItems.forEach(function (item) {
          item.addEventListener('mousedown', function (e) {
            e.target.click();
          });
        }) : null;
      }
    }) : null;

    var searchMenuElem = document.getElementById("search-menu");
    var activeItem = document.querySelector('#search-menu .dropdown-item.is-active');
    var activeIndex = null;
    var items = null;
    var searchContainerMaxHeight = 350;

    searchElem ? 
    searchElem.addEventListener('keydown', function(e) {
      if (window.innerWidth < 770) {
        return null;
      }

      if (e.key === 'Escape') {
        searchResult ? searchResult.setAttribute('data-display', 'none') : null;
        summaryContainer ? summaryContainer.setAttribute('data-display', 'block') : null;
      }

      var items = document.querySelectorAll('#search-menu .dropdown-item');
      var keyCode = e.which || e.keyCode;

      if (!items || !items.length) {
        return null;
      }
      
      if (e.key === 'ArrowDown' || keyCode === 40) {
        if (activeIndex === null) {
          activeIndex = 0;
          items[activeIndex].classList.remove('is-active');
        } else {
          items[activeIndex].classList.remove('is-active');
          activeIndex = activeIndex === items.length - 1 ? 0 : activeIndex + 1;
        }
        items[activeIndex].classList.add('is-active');

        let overflowedPixel = items[activeIndex].offsetTop + items[activeIndex].clientHeight - searchContainerMaxHeight;
        if (overflowedPixel > 0) {
          document.querySelector(".search-content").scrollTop += items[activeIndex].getBoundingClientRect().height;
        } else if (activeIndex === 0) {
          document.querySelector(".search-content").scrollTop = 0;
        }
      } else if (e.key === 'ArrowUp' || keyCode === 38) {
        if (activeIndex === null) {
          activeIndex = items.length - 1;
          items[activeIndex].classList.remove('is-active');
        } else {
          items[activeIndex].classList.remove('is-active');
          activeIndex = activeIndex === 0 ? items.length - 1 : activeIndex - 1;
        }
        items[activeIndex].classList.add('is-active');
        
        let overflowedPixel = items[activeIndex].offsetTop + items[activeIndex].clientHeight - searchContainerMaxHeight;
        if (overflowedPixel < 0) {
          document.querySelector(".search-content").scrollTop -= items[activeIndex].getBoundingClientRect().height;
        } else {
          document.querySelector(".search-content").scrollTop = overflowedPixel + items[activeIndex].getBoundingClientRect().height;
        }
      } else if (e.key === 'Enter' || keyCode === 13) {
        if (items[activeIndex] && items[activeIndex].getAttribute('href')) {
          location.href = items[activeIndex].getAttribute('href');
        }
      } else if (e.key === 'Escape' || keyCode === 27) {
        e.target.value = null;
        if (searchResults) {
          searchResults.classList.remove('is-active');
        }
      }
    }) : null;

    searchMobile ? 
    searchMobile.addEventListener('input', function(e) {
      if (!e.target.value) {
        let wrap = document.getElementById('search-mobile-results');
        while (wrap.firstChild) {
          wrap.removeChild(wrap.firstChild);
        }
        return null;
      }

      searchText = e.target.value;
      var results = fuse.search(e.target.value);
      renderSearchResultsMobile(searchText, results);
      if (enableSearchHighlight) {
        renderSearchHighlightResultsMobile(searchText, results);
      } else {
        renderSearchResultsMobile(searchText, results);
      }
    }) : null;
  


  
    var mobileSearchInputElem = document.querySelector('#search-mobile');
    var mobileSearchClassElem = document.querySelector('.mobile-search');
    var mobileSearchBtnElems = document.querySelectorAll('.navbar-search');
    var mobileSearchCloseBtnElem = document.querySelector('#search-mobile-close');
    var mobileSearchContainer = document.querySelector('#search-mobile-container');
    var mobileSearchResultsElem = document.querySelector('#search-mobile-results');
    var htmlElem = document.querySelector('html');

    if (mobileSearchClassElem) {
      mobileSearchClassElem.style.display = 'none';
    }

    mobileSearchBtnElems ? 
    mobileSearchBtnElems.forEach(function (elem, idx) {
      elem.addEventListener('click', function () {
        if (mobileSearchContainer) {
          mobileSearchContainer.style.display = 'block';
        }

        if (mobileSearchInputElem) {
          mobileSearchInputElem.focus();
        }

        if (htmlElem) {
          htmlElem.style.overflowY = 'hidden';
        }
      });
    }) : null;

    mobileSearchCloseBtnElem ? 
    mobileSearchCloseBtnElem.addEventListener('click', function() {
      if (mobileSearchContainer) {
        mobileSearchContainer.style.display = 'none';
      }

      if (mobileSearchInputElem) {
        mobileSearchInputElem.value = '';
      }
      
      if (mobileSearchResultsElem) {
        while (mobileSearchResultsElem.firstChild) {
          mobileSearchResultsElem.removeChild(mobileSearchResultsElem.firstChild);
        }
      }

      if (htmlElem) {
        htmlElem.style.overflowY = 'visible';
      }
    }) : null;

    mobileSearchInputElem ?
    mobileSearchInputElem.addEventListener('keydown', function(e) {
      var keyCode = e.which || e.keyCode;
      if (e.key === 'Escape' || keyCode === 27) {
        if (mobileSearchContainer) {
          mobileSearchContainer.style.display = 'none';
        }
        
        if (mobileSearchInputElem) {
          mobileSearchInputElem.value = '';
        }

        if (mobileSearchResultsElem) {
          while (mobileSearchResultsElem.firstChild) {
            mobileSearchResultsElem.removeChild(mobileSearchResultsElem.firstChild);
          }
        }
        if (htmlElem) {
          htmlElem.style.overflowY = 'visible';
        }
      }
    }) : null;
  


  
    function renderSearchResultsMain(searchText, results) {
      var searchBody = document.querySelector('.search-result__body');
      var originUl = searchBody.querySelector('ul');
      var ul = document.createElement('ul');
      
      if (!searchText) {
        searchResult ? searchResult.setAttribute('data-display', 'none') : null;
        summaryContainer ? summaryContainer.setAttribute('data-display', 'block') : null;
      } else if (results) {
        if (results && results.length) {
          results.forEach(function (result) {
            makeLi(ul, result);
          });

          searchResult ? searchResult.setAttribute('data-display', 'block') : null;
          summaryContainer ? summaryContainer.setAttribute('data-display', 'none') : null;
        }
      }

      originUl.parentNode.replaceChild(ul, originUl);
    }

    function renderSearchHighlightResultsMain(searchText, results) {
      var searchBody = document.querySelector('.search-result__body');
      var originUl = searchBody.querySelector('ul');
      var ul = document.createElement('ul');

      if (!searchText) {
        searchResult ? searchResult.setAttribute('data-display', 'none') : null;
        summaryContainer ? summaryContainer.setAttribute('data-display', 'block') : null;
      } else if (results) {
        if (results && results.length) {
          results.forEach(function (result) {
            makeHighlightLi(ul, result);
          });

          searchResult ? searchResult.setAttribute('data-display', 'block') : null;
          summaryContainer ? summaryContainer.setAttribute('data-display', 'none') : null;
        }
      }

      originUl.parentNode.replaceChild(ul, originUl);
    }
  
  });
</script>
    
    


<link rel="stylesheet" href="/css/main.min.css">


    
<meta name="description" content="" />


<meta name="keywords" content="network,http3">

<meta name="created" content="2022-07-10T00:00:00&#43;0000">
<meta name="modified" content="2022-07-10T00:00:00&#43;0000">
<meta property="article:published_time" content="2022-07-10T00:00:00&#43;0000">

<meta name="author" content="ruokeqx">


<meta property="og:site_name" content="ruokeqx&#39;s blog">
<meta property="og:title" content="QUIC&amp;HTTP3相关RFC文档阅读">
<meta property="og:url" content="https://ruokeqx.gitee.io/posts/quichttp3_related_rfc/">
<meta property="og:type" content="article">
<meta property="og:description" content="">

<meta name="generator" content="Hugo 0.100.2" />
<meta name="msapplication-TileColor" content="#fff">

<meta name="theme-color" content="#fff">

<meta name="msapplication-navbutton-color" content="#fff">

<meta name="apple-mobile-web-app-status-bar-style" content="#fff">

<link rel="canonical" href="https://ruokeqx.gitee.io/posts/quichttp3_related_rfc/">

<link rel="manifest" href="/manifest.json">

  
  <link rel="shortcut icon" href="/favicon.ico" type="image/x-icon">
  <link rel="icon" href="/favicon.png" sizes="any" type="image/png" />
  


    <script type="application/ld+json">
  {
    "@context": "https://schema.org",
    "@type": "WebPage",
    "headline": "QUIC\u0026HTTP3相关RFC文档阅读",
    "datePublished": "2022-07-10T00:00:00Z",
    "dateModified": "2022-07-10T00:00:00Z",
    "url" : "https://ruokeqx.gitee.io/posts/quichttp3_related_rfc/",
    "description": "简单看了以下几个QUIC和HTTP3相关RFC文档，对其设计有了一定了解。 RFC8999: Version-Independent Properties of QUIC RFC9000: QUIC: A UDP-Based Multiplexed and Secure Transport RFC9114: HTTP/3 RFC9204: …",
    "keywords": ["network","http3"],
    "mainEntityOfPage": {
      "@type": "WebPage",
      "@id": "https://ruokeqx.gitee.io"
    },
    "publisher": {
      "@type": "Organization",
      "name": "ruokeqx's blog",
      "url": "https://ruokeqx.gitee.io"
    }
  }
</script>

    
  
  







  <script async src="https://busuanzi.ibruce.info/busuanzi/2.3/busuanzi.pure.mini.js"></script>

    
</head>

<body id="root" class="theme__dark">
    <script>
        var localTheme = localStorage.getItem('theme');
        if (localTheme) {
            document.getElementById('root').className = 'theme__' + localTheme;
        }
    </script>
    <div id="container">
        





        <div class="wrapper" data-type="posts" data-kind="page">
            <nav class="navbar scrolling" role="navigation" aria-label="main navigation" data-dir="ltr">
  <div class="navbar__brand">
    
    <a href="/" title="Home" rel="home" class="navbar__logo-link">
      <img src="/logo.png" alt="Home" class="navbar__logo">
    </a>
    
    
      <a href="/" title="Home" rel="home" class="navbar__title-link">
        <h6 class="navbar__title">ruokeqx</h6>
      </a>
    
  </div>

  
<div class="theme theme-mobile" data-ani="true">
  <div class="dropdown">
    <button class="dropdown-trigger navbar__slide-down" aria-label="Select Theme Button" style="" data-ani="true">
      <svg xmlns="http://www.w3.org/2000/svg" width="22" height="22" viewBox="0 0 24 24"><path fill="none" d="M24 0H0v24h24V0z"/><path fill="currentColor" d="M6.34 7.93c-3.12 3.12-3.12 8.19 0 11.31C7.9 20.8 9.95 21.58 12 21.58s4.1-.78 5.66-2.34c3.12-3.12 3.12-8.19 0-11.31l-4.95-4.95c-.39-.39-1.02-.39-1.41 0L6.34 7.93zM12 19.59c-1.6 0-3.11-.62-4.24-1.76C6.62 16.69 6 15.19 6 13.59s.62-3.11 1.76-4.24L12 5.1v14.49z"/></svg>      
    </button>
    <div class="dropdown-content select-theme">
      
        
        <a href="#" class="dropdown-item select-theme__item is-active">
          dark
        </a>
        
        <a href="#" class="dropdown-item select-theme__item ">
          light
        </a>
        
        <a href="#" class="dropdown-item select-theme__item ">
          hacker
        </a>
        
        <a href="#" class="dropdown-item select-theme__item ">
          solarized
        </a>
        
        <a href="#" class="dropdown-item select-theme__item ">
          kimbie
        </a>
        
      
    </div>
  </div>
</div>


<div class="mobile-search__btn navbar-search" data-ani="true">
  <svg xmlns="http://www.w3.org/2000/svg" width="22" height="22" fill="currentColor" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M15.5 14h-.79l-.28-.27c1.2-1.4 1.82-3.31 1.48-5.34-.47-2.78-2.79-5-5.59-5.34-4.23-.52-7.79 3.04-7.27 7.27.34 2.8 2.56 5.12 5.34 5.59 2.03.34 3.94-.28 5.34-1.48l.27.28v.79l4.25 4.25c.41.41 1.08.41 1.49 0 .41-.41.41-1.08 0-1.49L15.5 14zm-6 0C7.01 14 5 11.99 5 9.5S7.01 5 9.5 5 14 7.01 14 9.5 11.99 14 9.5 14z"/></svg>
</div>

<div id="search-mobile-container" class="mobile-search hide" data-dir="ltr">
  <div class="mobile-search__top">
    <input id="search-mobile" type="text" aria-label="Mobile Search" placeholder="Search" class="mobile-search__top--input"/>
    <div id="search-mobile-close" class="mobile-search__top--icon">
      <svg xmlns="http://www.w3.org/2000/svg" width="22" height="22" viewBox="0 0 24 24"><path opacity=".87" fill="none" d="M0 0h24v24H0V0z"/><path fill="currentColor" d="M12 2C6.47 2 2 6.47 2 12s4.47 10 10 10 10-4.47 10-10S17.53 2 12 2zm0 18c-4.41 0-8-3.59-8-8s3.59-8 8-8 8 3.59 8 8-3.59 8-8 8zm3.59-13L12 10.59 8.41 7 7 8.41 10.59 12 7 15.59 8.41 17 12 13.41 15.59 17 17 15.59 13.41 12 17 8.41z"/></svg>
    </div>
  </div>
  <div id="search-mobile-results" class="mobile-search__body">
    
  </div>
</div>


<a role="button" class="navbar__burger" aria-label="menu" aria-expanded="false"
  data-ani="true">
  <span aria-hidden="true"></span>
  <span aria-hidden="true"></span>
  <span aria-hidden="true"></span>
</a>
<div class="navbarm__collapse" data-open="false">
  <ul dir="ltr">
    
    
      
      
      
      

      
        <li class="navbarm__menu--item active">
          <a href="/posts">Posts</a>
        </li>
      
      
    
      
      
      
      

      
        <li class="navbarm__menu--item ">
          <a href="/archive">Archive</a>
        </li>
      
      
    
      
      
      
      

      
        <li class="navbarm__menu--item ">
          <a href="/about">About</a>
        </li>
      
      
    

    
      <li class="navbarm__menu--item ">
        <a href="/tags" class="navbarm__menu--term" data-index="0">
          Tags
        </a>
      </li>
    
      <li class="navbarm__menu--item ">
        <a href="/categories" class="navbarm__menu--term" data-index="1">
          Categories
        </a>
      </li>
    
      <li class="navbarm__menu--item ">
        <a href="/series" class="navbarm__menu--term" data-index="2">
          Series
        </a>
      </li>
    
  </ul>
</div>
  <div class="navbar__menu">
  
  
  
<div class="theme" data-ani="true">
  <div class="dropdown">
    <button class="dropdown-trigger navbar__slide-down" aria-label="Select Theme Button" data-ani="true">
      <svg xmlns="http://www.w3.org/2000/svg" width="22" height="22" viewBox="0 0 24 24"><path fill="none" d="M24 0H0v24h24V0z"/><path fill="currentColor" d="M6.34 7.93c-3.12 3.12-3.12 8.19 0 11.31C7.9 20.8 9.95 21.58 12 21.58s4.1-.78 5.66-2.34c3.12-3.12 3.12-8.19 0-11.31l-4.95-4.95c-.39-.39-1.02-.39-1.41 0L6.34 7.93zM12 19.59c-1.6 0-3.11-.62-4.24-1.76C6.62 16.69 6 15.19 6 13.59s.62-3.11 1.76-4.24L12 5.1v14.49z"/></svg>      
    </button>
    <div class="dropdown-content select-theme">
      
        
        <a href="#" class="dropdown-item select-theme__item is-active">
          dark
        </a>
        
        <a href="#" class="dropdown-item select-theme__item ">
          light
        </a>
        
        <a href="#" class="dropdown-item select-theme__item ">
          hacker
        </a>
        
        <a href="#" class="dropdown-item select-theme__item ">
          solarized
        </a>
        
        <a href="#" class="dropdown-item select-theme__item ">
          kimbie
        </a>
        
      
    </div>
  </div>
</div>

  
  
  
  
  
  
  
  <a href="/posts" class="navbar__menu-item navbar__slide-down active" dir="ltr" data-ani="true">Posts</a>
  
  
  
  
  
  
  
  <a href="/archive" class="navbar__menu-item navbar__slide-down " dir="ltr" data-ani="true">Archive</a>
  
  
  
  
  
  
  
  <a href="/about" class="navbar__menu-item navbar__slide-down " dir="ltr" data-ani="true">About</a>
  
  
</div>
</nav>
            
            

<main class="single__main main">
  
    <nav class="breadcrumb hide" aria-label="breadcrumbs">
  <script>document.querySelector('.breadcrumb').classList.remove('hide')</script>
  <ol>
    
  
  
  
  
  
  <li >
    
      <a href="https://ruokeqx.gitee.io/" class="capitalize">ruokeqx&#39;s blog</a>
    
  </li>
  
  
  <li >
    
      <a href="https://ruokeqx.gitee.io/posts/" class="capitalize">Posts</a>
    
  </li>
  
  
  <li  class="is-active" >
    
      <span>QUIC&amp;HTTP3相关RFC文档阅读</span>
    
  </li>
  
  </ol>
  
</nav>
  
  
  <div class="single ">
    <div class="single__nojs">This page looks best with JavaScript enabled</div>
    <script>document.querySelector('.single').classList.remove('hide'); document.querySelector('.single__nojs').classList.add('hide');</script>
    <h2 class="single__title" data-ani="true">QUIC&amp;HTTP3相关RFC文档阅读</h2>
    <h3 class="single__subtitle"></h3>
    <div class="single__meta">
      
<div class="single__infos">
  <time class="single__info" title="Written At">📅&nbsp;Jul 10, 2022 </time>
  
  &nbsp;&middot;&nbsp; <span class="single__info" title="Reading Time"> ☕&nbsp;35&nbsp;min read </span>
  
  <span class="single__info">
     &middot; 👀<span id="busuanzi_value_page_pv">...</span> views
  </span>
</div>

      
<ul class="single__tags caption">
  
  🏷️
  

  <li><a href="https://ruokeqx.gitee.io/tags/network/" class="single__tag" title="network">#network</a></li>

  <li><a href="https://ruokeqx.gitee.io/tags/http3/" class="single__tag" title="http3">#http3</a></li>

</ul>

    </div>
    <article class="single__contents" data-dir="ltr" data-ani="true">
      
      <p>简单看了以下几个QUIC和HTTP3相关RFC文档，对其设计有了一定了解。</p>
<p>RFC8999: Version-Independent Properties of QUIC</p>
<p>RFC9000: QUIC: A UDP-Based Multiplexed and Secure Transport</p>
<p>RFC9114: HTTP/3</p>
<p>RFC9204: QPACK: Field Compression for HTTP/3</p>
<h2 id="rfc8999">RFC8999</h2>
<p>RFC8999十分简单 甚至比一些简短的论文还要短，他的目录也十分简单，毕竟只是定义了QUIC协议的一些通识信息。</p>
<p>内容不多，最关键的就是描述了一个长包短包，ID和版本及版本协商相关内容。其中定义结构通过观察流量包内容可以得到验证</p>
<p><img src="/images/posts/QUIC&amp;HTTP_RFC/image-20220710153659482.png" alt="image-20220710153659482" /></p>
<p>上面抓到的Version id都是1，基于RFC9000实现。查看Wireshark源码[wireshark/epan/dissectors/packet-quic.c](<a href="https://gitlab.com/wireshark/wireshark/-/blob/master/epan/dissectors/packet-quic.c">epan/dissectors/packet-quic.c · master · Wireshark Foundation / wireshark · GitLab</a>)可以看到其实已经有很多公司内部实现的协议版本了。</p>
<p>以下是原文内容</p>
<h3 id="1-quic的一个高度抽象的描述">1. QUIC的一个高度抽象的描述</h3>
<p>QUIC 是两个端点之间的面向连接的协议。 这些端点交换 UDP 数据报。 这些 UDP 数据报包含 QUIC 数据包。 QUIC 端点使用 QUIC 数据包来建立 QUIC 连接，这是这些端点之间的共享协议状态。</p>
<h3 id="2-所有quic版本固定的属性">2. 所有QUIC版本固定的属性</h3>
<p>除了提供安全、多路复用的传输功能，QUIC《<a href="https://autumnquiche.github.io/RFC8999_Chinese_Translation/#QUIC_TRANSPORT">QUIC协议</a>》还支持版本协商。这将使得协议能够在以后的岁月中为适应新的需求而更新，而协议的诸多特性可以随着版本的迭代而不断改变。</p>
<p>本文阐述QUIC的一些在新的QUIC版本开发及部署的过程中依旧保持不变的属性。所有这些不变属性都与IP版本无关。</p>
<p>本文的主要目标是确保后续QUIC新版本的迭代。通过陈述QUIC的这些不可更改的属性，本文试图维持QUIC终端对QUIC协议任何其他方面的改动进行协商的能力。因此，这也保证了暴露到一条QUIC连接两个终端之外的信息量最少。QUIC协议在本文明确禁止之外的任何方面，都是可以在不同版本之间修改的。</p>
<p>附录A包含一份非详尽的清单，列出了一些基于对QUIC版本1的了解可能做出的不正确的猜想，这些不适用于QUIC的任何版本。</p>
<h3 id="3-规约及定义">3. 规约及定义</h3>
<h3 id="4-标准规范">4. 标准规范</h3>
<p>复杂的字段被命名后，由紧随命名的一个以一对花括号括起来的字段列表描述，列表中的字段以逗号分隔。</p>
<p>单个字段包括长度信息、带正号的定值、可选值或本字段的副本。单个字段使用下述标准规范，且所有长度都以比特为单位：</p>
<p><code>x (A)</code>: 表示<code>x</code>是<code>A</code>比特长度</p>
<p><code>x (A..B)</code>: 表示<code>x</code>的长度可以是从<code>A</code>到<code>B</code>的所有值，省略<code>A</code>表示最小零位，并且省略<code>B</code>表示没有设置上限。这种格式的值总是以字符边界结束。</p>
<p><code>x (L) = C</code>: 表示<code>x</code>有一个定值<code>C</code>，且<code>x</code>的长度为<code>L</code>，<code>L</code>可以用上述任何长度格式</p>
<p><code>x (L) ...</code>: 表示<code>x</code>重复0次或以上次数，且每个实例长度为<code>L</code></p>
<p>本文使用网络字节序(大端序)</p>
<p>示例结构：</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span><span class="lnt">6
</span><span class="lnt">7
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="n">Example</span> <span class="n">Structure</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="n">One</span><span class="o">-</span><span class="n">bit</span> <span class="n">Field</span> <span class="p">(</span><span class="mi">1</span><span class="p">),</span>
</span></span><span class="line"><span class="cl"> <span class="mi">7</span><span class="o">-</span><span class="n">bit</span> <span class="n">Field</span> <span class="n">with</span> <span class="n">Fixed</span> <span class="n">Value</span> <span class="p">(</span><span class="mi">7</span><span class="p">)</span> <span class="o">=</span> <span class="mi">61</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="n">Arbitrary</span><span class="o">-</span><span class="n">Length</span> <span class="n">Field</span> <span class="p">(..),</span>
</span></span><span class="line"><span class="cl"> <span class="n">Variable</span><span class="o">-</span><span class="n">Length</span> <span class="n">Field</span> <span class="p">(</span><span class="mf">8..24</span><span class="p">),</span>
</span></span><span class="line"><span class="cl"> <span class="n">Repeated</span> <span class="n">Field</span> <span class="p">(</span><span class="mi">8</span><span class="p">)</span> <span class="p">...,</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></td></tr></table>
</div>
</div><h3 id="5-quic-packets">5. QUIC Packets</h3>
<p>QUCI终端之间交换包含一个或多个QUIC数据包的UDP报文。本章描述QUIC包的不变特性。一个版本的QUIC准许多个QUIC数据包包含于同一个UDP报文里，但是其不变的特性只要求报文里的首个数据包保持。</p>
<p>QUIC定义了两类数据包头：长包头与短包头。有长包头的数据包由其首个字节的首个比特位设置为1判定，而短包头数据包这个比特位设置为0。</p>
<p>QUIC数据包可能被完全保护，包括包头。然而，QUIC版本协商包不会被完全保护，详见第6章。</p>
<p>除了这里描述的值之外，QUIC数据包的有效负载是由各个版本决定且任意长度的。</p>
<h4 id="51-长header">5.1 长Header</h4>
<p>长Header格式</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="n">Long</span> <span class="n">Header</span> <span class="n">Packet</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="n">Header</span> <span class="n">Form</span> <span class="p">(</span><span class="mi">1</span><span class="p">)</span> <span class="o">=</span> <span class="mi">1</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="n">Version</span><span class="o">-</span><span class="n">Specific</span> <span class="n">Bits</span> <span class="p">(</span><span class="mi">7</span><span class="p">),</span>
</span></span><span class="line"><span class="cl"> <span class="n">Version</span> <span class="p">(</span><span class="mi">32</span><span class="p">),</span>
</span></span><span class="line"><span class="cl"> <span class="n">Destination</span> <span class="n">Connection</span> <span class="n">ID</span> <span class="n">Length</span> <span class="p">(</span><span class="mi">8</span><span class="p">),</span>
</span></span><span class="line"><span class="cl"> <span class="n">Destination</span> <span class="n">Connection</span> <span class="n">ID</span> <span class="p">(</span><span class="mf">0..2040</span><span class="p">),</span>
</span></span><span class="line"><span class="cl"> <span class="n">Source</span> <span class="n">Connection</span> <span class="n">ID</span> <span class="n">Length</span> <span class="p">(</span><span class="mi">8</span><span class="p">),</span>
</span></span><span class="line"><span class="cl"> <span class="n">Source</span> <span class="n">Connection</span> <span class="n">ID</span> <span class="p">(</span><span class="mf">0..2040</span><span class="p">),</span>
</span></span><span class="line"><span class="cl"> <span class="n">Version</span><span class="o">-</span><span class="n">Specific</span> <span class="n">Data</span> <span class="p">(..),</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>QUIC长包头数据包其首字节最高比特位设置为1，其余比特位则视具体版本而定。</p>
<p>随后的四个字节包含一个32位版本字段，关于版本详见第5.4章。</p>
<p>接下来的一个字节包含紧随其后的目标连接ID字段的长度，且该长度值以字节计数，并被编码为一个8位无符号整数。目标连接ID字段紧随目标连接ID长度字段，其长度在0到255字节之间。连接ID详见第5.3章。</p>
<p>接下来的一个字节包含紧随其后的源连接ID字段的长度，且该长度值以字节计数，并被编码为一个8位无符号整数。源连接ID字段紧随源连接ID长度字段，其长度在0-255字节之间。</p>
<p>数据包接下来剩余字段包含与QUIC版本特定相关的内容。</p>
<h4 id="52-短header">5.2 短Header</h4>
<p>短Header格式</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span><span class="lnt">6
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="n">Short</span> <span class="n">Header</span> <span class="n">Packet</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="n">Header</span> <span class="n">Form</span> <span class="p">(</span><span class="mi">1</span><span class="p">)</span> <span class="o">=</span> <span class="mi">0</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="n">Version</span><span class="o">-</span><span class="n">Specific</span> <span class="n">Bits</span> <span class="p">(</span><span class="mi">7</span><span class="p">),</span>
</span></span><span class="line"><span class="cl"> <span class="n">Destination</span> <span class="n">Connection</span> <span class="n">ID</span> <span class="p">(..),</span>
</span></span><span class="line"><span class="cl"> <span class="n">Version</span><span class="o">-</span><span class="n">Specific</span> <span class="n">Data</span> <span class="p">(..),</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>短包头QUIC数据包的首字节的最高位设置为0。</p>
<p>短包头数据包紧随首字节之后是一个目标连接ID。短包头不会包含目标连接ID长度、源连接ID长度、源连接ID或版本字段。目标连接ID的长度不会编码在短包头数据包里，也不会受限于这个特性。</p>
<p>数据包接下来剩余字段有与版本特定相关的语义。</p>
<h4 id="53-连接id">5.3 连接ID</h4>
<p>连接ID是一个任意长度的不透明字段。</p>
<p>连接ID的主要功能是确保底层协议（UDP、IP及更底层的协议栈）发生地址变更时不会导致一个QUIC连接的数据包被传输到错误的QUIC终端上。连接ID由终端及支持的中间设备用以确保每个数据包能够被调度到相应终端的正确实体上。对于终端而言，连接ID用于标识数据包对应的QUIC连接。</p>
<p>连接ID由每个终端根据版本特定的方式选择，而同一个QUIC连接的数据包可能使用不同的连接ID。</p>
<h4 id="54-版本">5.4 版本</h4>
<p>版本字段包含一个4字节标识符。该值可供终端用以标识一个QUIC版本。值为<code>0x00000000</code>的版本字段保留给版本协商使用，详见第6章，而任何其余值均可能有效。</p>
<p>本文描述的属性适用于所有版本的QUIC。不符合本文所述属性的协议不是QUIC协议。后续文档可以给某个特定QUIC版本或一系列QUIC版本增加其他的属性。</p>
<h3 id="6-版本协商">6. 版本协商</h3>
<p>QUIC终端收到一个带长包头的数据包及一个其不能理解或不支持的版本时，就可能回复一个版本协商包。短包头数据包不会触发版本协商。</p>
<p>版本协商包设置上首个字节的高位，也就是说它是一个在第5.1章定义的长包头数据包。版本协商包可以通过其版本字段识别，因为这个字段会被设置为<code>0x00000000</code>。</p>
<p>版本协商包</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="n">Version</span> <span class="n">Negotiation</span> <span class="n">Packet</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="n">Header</span> <span class="n">Form</span> <span class="p">(</span><span class="mi">1</span><span class="p">)</span> <span class="o">=</span> <span class="mi">1</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="n">Unused</span> <span class="p">(</span><span class="mi">7</span><span class="p">),</span>
</span></span><span class="line"><span class="cl"> <span class="n">Version</span> <span class="p">(</span><span class="mi">32</span><span class="p">)</span> <span class="o">=</span> <span class="mi">0</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="n">Destination</span> <span class="n">Connection</span> <span class="n">ID</span> <span class="n">Length</span> <span class="p">(</span><span class="mi">8</span><span class="p">),</span>
</span></span><span class="line"><span class="cl"> <span class="n">Destination</span> <span class="n">Connection</span> <span class="n">ID</span> <span class="p">(</span><span class="mf">0..2040</span><span class="p">),</span>
</span></span><span class="line"><span class="cl"> <span class="n">Source</span> <span class="n">Connection</span> <span class="n">ID</span> <span class="n">Length</span> <span class="p">(</span><span class="mi">8</span><span class="p">),</span>
</span></span><span class="line"><span class="cl"> <span class="n">Source</span> <span class="n">Connection</span> <span class="n">ID</span> <span class="p">(</span><span class="mf">0..2040</span><span class="p">),</span>
</span></span><span class="line"><span class="cl"> <span class="n">Supported</span> <span class="n">Version</span> <span class="p">(</span><span class="mi">32</span><span class="p">)</span> <span class="p">...,</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>版本协商包只有首字节最重要的那个比特位有着任意定义的值。其剩余的7个比特位标记为“未使用”，在发送的时候可以被设置为任意值，且必须被接收端忽略。</p>
<p>版本协商包紧随源连接ID字段后面的是一个支持版本字段的列表，该列表每个字段标识终端能够支持的版本（也就是客户端支持的QUIC版本的版本号挨个列下去）。版本协商包不包含其他字段，终端必须忽略不包含支持版本字段或包含不完整版本值的包。</p>
<p>版本协商包不使用完全的或加密的保护。某些特定的QUIC版本可能包含准许终端鉴别支持版本列表里的值是否存在修改或损坏的协议手段。</p>
<p>终端必须在其目标连接ID字段包含它收到的数据包的源连接ID值。必须将收到数据包的目标连接ID字段值复制给源连接ID字段，该值是客户端随机产生的。回显两个连接ID给客户端一些保证，表明服务端收到了包，且版本协商包不是由对其不可见的攻击者生成的。</p>
<p>终端收到版本协商包后，可以在随后的数据包中更改QUIC版本。终端更改QUIC版本的条件将取决于其选择的版本。</p>
<p>《QUIC协议》详细描述了支持QUIC版本1的终端如何创建及处理一个版本协商包。</p>
<h3 id="7-安全及隐私考量">7. 安全及隐私考量</h3>
<p>中间件可能能够识别特定版本的QUIC的一些特性，并假设其他版本的QUIC表现出类似特征时，其底层正在表达一致的语义。这样的特性有好几个，详见附录A。QUIC版本1已经做了一些工作消除或隐藏一些可见的特征，但是许多这样的特性仍然维持现状。后续其他QUIC版本可能改变设计从而表现出不同的特征。</p>
<p>QUIC版本号不会出现在所有QUIC数据包中，这意味着以一个基于版本的特征从一条流中可靠地提取信息需要中间件为每个连接ID保留状态。</p>
<p>本文所述版本协商包不会被完整保护，仅仅对攻击者的介入做了适度保护。如果终端试图改用不同的QUIC版本，那么它必须验证版本协商包的语义内容。</p>
<h4 id="附录a不正确的猜想">附录A：不正确的猜想</h4>
<p>QUIC版本1《<a href="https://autumnquiche.github.io/RFC8999_Chinese_Translation/#QUIC_TRANSPORT">QUIC协议</a>》有一系列特性没有被保护为外部不可见，但是一般认为可以在后续的QUIC版本中更改。</p>
<p>本章列出了基于QUIC版本1的了解可能做出的一些错误猜想，其中一些陈述甚至对QUIC版本1也是错误的。这个列举并不充分，目的在于做一些阐述。</p>
<p>对于一个QUIC版本，下述任意一条甚至所有的陈述都可能是错的：</p>
<ul>
<li>QUIC使用TLS《QUIC TLS》，而链路上一些TLS的信息是可见的。</li>
<li>QUIC长包头只在连接建立阶段发生更改。</li>
<li>五元组上的每条流都会包含一个连接建立过程。</li>
<li>一条流的前几个包使用长包头。</li>
<li>在一段长时间的静默前的最后一个包只包含一个确认信息。</li>
<li>QUIC使用关联数据加密认证（AEAD）函数（AEAD_AES_128_GCM，详见RFC5116保护在连接建立阶段交换的数据包。</li>
<li>QUIC数据包号是加密的，且是数据包的初始加密字节。</li>
<li>QUIC数据包号每发送一个包递增1。</li>
<li>客户端发送的首个QUIC握手包不能小于一个特定尺寸。</li>
<li>QUIC规定客户端发送第一个包。</li>
<li>QUIC数据包首字节的第二个比特位总是设置为1的（0x40）。</li>
<li>QUIC版本协商包只会由服务端发出。</li>
<li>QUIC连接ID很少发生改变。</li>
<li>QUIC终端会在发送完一个版本协商包后改变QUIC版本。</li>
<li>QUIC长包头的版本字段在两个方向上都是一样的。</li>
<li>QUIC包版本字段有一个代表某QUIC版本的值意味着连接用的就是相应的QUIC版本。</li>
<li>任何一对QUIC终端之间一次只有一个QUIC连接建联。</li>
</ul>
<h2 id="rfc9000">RFC9000</h2>
<p>QUIC是一个面向连接的协议，在客户端及服务端之间建立有状态的交互。</p>
<p>QUIC握手由密钥协商及传输参数协商组成。QUIC集成了TLS握手《TLS 1.3》，同时以自定义的帧保护数据包。更多关于TLS与QUIC集成的细节描述详见《QUIC-TLS》。握手过程被设计成支持尽早交换应用数据（0-RTT），包含一个需要通过某种形式的提前交流或配置来开启的客户端选项。</p>
<p>终端通过QUIC交流是以交互QUIC数据包的形式实现的。大多数数据包装载着一个或多个在终端间搬运控制信息和应用数据的帧。QUIC会验证每个包的内容，并根据实际情况对每个数据包进行加密。QUIC数据包通过UDP报文《UDP》传输从而能够更好地支持现有的系统及网络环境。</p>
<p>应用层协议通过流在QUIC连接上交换信息，每条流都是有序的字节序列。流的类型分两种：双向流，支持双端发送数据；以及单向流，只支持一端发送数据。QUIC使用一种基于额度的方案来限制流的创建以及每条流可以发送的数据量。</p>
<p>QUIC以提供必要反馈的方式实现可靠传输及拥塞控制，《QUIC恢复》第6章描述了QUIC的一种数据丢失及恢复算法；QUIC通过拥塞控制避免网络拥塞，《QUIC恢复》第7章描述了QUIC的一种典型拥塞控制算法。</p>
<p>QUIC连接不会严格限制在一条单独的网络通道上。连接迁移根据连接标识符将连接迁移到一个新的网络通道上。当前版本QUIC只支持客户端进行连接迁移。在改变网络或地址映射——如NAT重定向——后，这个设计使连接仍然能够继续下去而不会断开。</p>
<p>有多种方式可以关闭连接。应用程序可以平滑关闭连接；双端可以协商一个超时时间段在超时后关闭连接；触发错误能够立即断开连接；一端失去状态后也能通过一种无状态机制关闭连接。</p>
<p><code>文档结构</code></p>
<p>流是QUIC支持的基本服务抽象层。</p>
<ul>
<li>第2章描述流相关的核心概念，</li>
<li>第3章提供一个流状态的参考模型，</li>
<li>第4章概述流量控制的过程。</li>
</ul>
<p>连接是QUIC终端交流的上下文。</p>
<ul>
<li>第5章描述连接相关的核心概念，</li>
<li>第6章描述版本协商</li>
<li>第7章详细描述连接建立的过程，</li>
<li>第8章描述地址验证及危险的拒绝服务迁移攻击，</li>
<li>第9章描述终端如何将一个连接迁移到新的网络通道上，</li>
<li>第10章列举关闭一个已打开连接的各个方式，以及</li>
<li>第11章给流与连接错误处理提供指导。</li>
</ul>
<p>数据包和帧是QUIC交流的基本单元。</p>
<p>第12章描述数据包与帧相关的概念，<br />
第13章定义数据传输、重传和确认的模型，以及<br />
第14章描述指定携带QUIC数据包的数据报大小的规则。</p>
<p>最后，QUIC协议要素的编码细节描述在：</p>
<ul>
<li>第15章版本，</li>
<li>第16章整型编码，</li>
<li>第17章数据包头部，</li>
<li>第18章传输参数，</li>
<li>第19章帧，以及</li>
<li>第20章错误。</li>
</ul>
<p>常用术语：</p>
<p>QUIC：本文描述的传输协议。QUIC是名称，不是首字母缩写。</p>
<p>终端（Endpoint）：一个能够以创建、接收及处理QUIC数据包参与QUIC连接的实体。QUIC终端有两种类型：客户端（client）及服务端（server）。</p>
<p>QUIC数据包：QUIC的一个可以封装进UDP报文中的完整处理单元。单个UDP报文可以封装进一个或多个QUIC数据包。</p>
<p>ACK触发包：一个包含除确认帧（ACK）、填充帧（PADDING）及连接关闭帧（CONNECTION_CLOSE）外的帧的QUIC数据包。接收方收到这类包会发确认，详见第13.2.1章。</p>
<p>帧：一个结构化的协议信息单元。帧有多种类型，不同类型的帧携带不同类型的信息。帧由QUIC数据包承载。</p>
<p>地址：当使用不受限制，由IP版本、IP地址及UDP端口号构成的元组表示网络通道的一端。</p>
<p>连接ID：终端用来标识一条QUIC连接的标识符。每个终端选择一个或多个连接ID，从而在对端发送给本端的QUIC包中包含这些连接ID。该值对对端是不透明的。</p>
<p>流：QUIC连接上一个单向或双向的有序字节通道。一个QUIC连接可以同时承载多条流。</p>
<p>应用：一个使用QUIC发送及接收数据的实体</p>
<p>字段信息表述同RFC8999<br />
示例结构体</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="n">Example</span> <span class="n">Structure</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="n">One</span><span class="o">-</span><span class="n">bit</span> <span class="n">Field</span> <span class="p">(</span><span class="mi">1</span><span class="p">),</span>
</span></span><span class="line"><span class="cl"> <span class="mi">7</span><span class="o">-</span><span class="n">bit</span> <span class="n">Field</span> <span class="n">with</span> <span class="n">Fixed</span> <span class="n">Value</span> <span class="p">(</span><span class="mi">7</span><span class="p">)</span> <span class="o">=</span> <span class="mi">61</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="n">Field</span> <span class="n">with</span> <span class="n">Variable</span><span class="o">-</span><span class="n">Length</span> <span class="n">Integer</span> <span class="p">(</span><span class="n">i</span><span class="p">),</span>
</span></span><span class="line"><span class="cl"> <span class="n">Arbitrary</span><span class="o">-</span><span class="n">Length</span> <span class="n">Field</span> <span class="p">(..),</span>
</span></span><span class="line"><span class="cl"> <span class="n">Variable</span><span class="o">-</span><span class="n">Length</span> <span class="n">Field</span> <span class="p">(</span><span class="mf">8..24</span><span class="p">),</span>
</span></span><span class="line"><span class="cl"> <span class="n">Field</span> <span class="n">With</span> <span class="n">Minimum</span> <span class="n">Length</span> <span class="p">(</span><span class="mf">16.</span><span class="p">.),</span>
</span></span><span class="line"><span class="cl"> <span class="n">Field</span> <span class="n">With</span> <span class="n">Maximum</span> <span class="n">Length</span> <span class="p">(.</span><span class="mf">.128</span><span class="p">),</span>
</span></span><span class="line"><span class="cl"> <span class="p">[</span><span class="n">Optional</span> <span class="n">Field</span> <span class="p">(</span><span class="mi">64</span><span class="p">)],</span>
</span></span><span class="line"><span class="cl"> <span class="n">Repeated</span> <span class="n">Field</span> <span class="p">(</span><span class="mi">8</span><span class="p">)</span> <span class="p">...,</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></td></tr></table>
</div>
</div><h3 id="0x2流">0x2、流</h3>
<p>流ID的最小有效位（0x01）标识流的发起者。客户端发起的流的ID是偶数（该位被置为0），服务端发起的流的ID是奇数（该位被置为1）。</p>
<p>流ID的次小有效位（0x02）标识流是双向流（该位被置为0）抑或单向流（该位被置为1）。</p>
<table>
<thead>
<tr>
<th align="left">位</th>
<th align="left">流类型</th>
</tr>
</thead>
<tbody>
<tr>
<td align="left">0x00</td>
<td align="left">客户端创建的双向流</td>
</tr>
<tr>
<td align="left">0x01</td>
<td align="left">服务端创建的双向流</td>
</tr>
<tr>
<td align="left">0x02</td>
<td align="left">客户端创建的单向流</td>
</tr>
<tr>
<td align="left">0x03</td>
<td align="left">服务端创建的单向流</td>
</tr>
</tbody>
</table>
<p>表格1：流类型</p>
<p>每种流类型的流空间从其最小值开始（依次从0x00到0x03）；每种流的每个流ID根据创建顺序依次线性递增。如果不按顺序地使用了一个流ID，将导致相同流类型的所有具有更小的流ID的流都被开启。</p>
<p>终端可以从一条流的同一个偏移位置多次接收数据。如果数据已经被接收过了，就可以直接被丢弃。</p>
<h4 id="0x24流操作">0x24、流操作</h4>
<p>本文没有定义QUIC API，而是定义了一系列流操作相关的函数可以用于应用层协议的构建。应用层协议可以假定QUIC有关实现提供了本章描述的操作对应的接口。为一个特定应用层协议设计实现的QUIC协议可能仅仅提供该协议需要的这些操作。</p>
<p>在流的发送部分，应用层协议可以：</p>
<ul>
<li>写数据，只有当流量控制给数据写出留足空间（第4.1章）才能成功写出；</li>
<li>结束流（清理并关闭），发送一个设置FIN位为1的流帧（第19.8章）；</li>
<li>重置流（中止并关闭），当流未处在终止状态时发送一个RESET_STREAM帧（第19.4章）。</li>
</ul>
<p>在流的接收部分，应用层协议可以：</p>
<ul>
<li>读数据，以及</li>
<li>中止读取流数据并请求关闭流，该操作可能需要发送STOP_SENDING帧（第19.5章）。</li>
</ul>
<p>应用层协议也可以请求在流状态改变的时候收到通知信息，包括当对端开启或重置流、对端中止流数据读取、有新数据可以读取、以及数据可以写出或因流控不能写出。</p>
<h3 id="0x3流状态">0x3、流状态</h3>
<p>本章描述流的发送及接收相关组件。有两个状态机需要描述：一个是关于终端传输数据（第3.1章）的流，另一个是关于终端接收数据（第3.2章）的流。</p>
<p>单向流用到发送或接收的其中一个状态机，取决于流类型及终端角色。双向流双端都会用到两个状态机。在极大程度上，不论单向流还是双向流，在使用这两个状态机上是没有区别的。相对而言打开一条双向流会稍微复杂一些，因为同时打开发送和接收端意味着在两个方向上同时打开流。</p>
<p>本章展示的状态机极具信息量。本文使用流状态描述不同类型帧在何时以何种方式发送的相关规则，以及当收到不同类型的帧时应作出的反应。即使这些状态机目的在于指导如何实现QUIC协议，但其并不意味着限制QUIC实现的方式。一个QUIC实现完全可以定义不同的状态机，只要其行为与本文所述状态机的具体实现一致即可。</p>
<h4 id="0x31发送流状态">0x31、发送流状态</h4>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span><span class="lnt">18
</span><span class="lnt">19
</span><span class="lnt">20
</span><span class="lnt">21
</span><span class="lnt">22
</span><span class="lnt">23
</span><span class="lnt">24
</span><span class="lnt">25
</span><span class="lnt">26
</span><span class="lnt">27
</span><span class="lnt">28
</span><span class="lnt">29
</span><span class="lnt">30
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">       o
</span></span><span class="line"><span class="cl">       <span class="p">|</span> Create Stream <span class="o">(</span>Sending<span class="o">)</span>
</span></span><span class="line"><span class="cl">       <span class="p">|</span> Peer Creates Bidirectional Stream
</span></span><span class="line"><span class="cl">       v
</span></span><span class="line"><span class="cl">   +-------+
</span></span><span class="line"><span class="cl">   <span class="p">|</span> Ready <span class="p">|</span> Send RESET_STREAM
</span></span><span class="line"><span class="cl">   <span class="p">|</span>       <span class="p">|</span>-----------------------.
</span></span><span class="line"><span class="cl">   +-------+                       <span class="p">|</span>
</span></span><span class="line"><span class="cl">       <span class="p">|</span>                           <span class="p">|</span>
</span></span><span class="line"><span class="cl">       <span class="p">|</span> Send STREAM /             <span class="p">|</span>
</span></span><span class="line"><span class="cl">       <span class="p">|</span>      STREAM_DATA_BLOCKED  <span class="p">|</span>
</span></span><span class="line"><span class="cl">       v                           <span class="p">|</span>
</span></span><span class="line"><span class="cl">   +-------+                       <span class="p">|</span>
</span></span><span class="line"><span class="cl">   <span class="p">|</span> Send  <span class="p">|</span> Send RESET_STREAM     <span class="p">|</span>
</span></span><span class="line"><span class="cl">   <span class="p">|</span>       <span class="p">|</span>----------------------&gt;<span class="p">|</span>
</span></span><span class="line"><span class="cl">   +-------+                       <span class="p">|</span>
</span></span><span class="line"><span class="cl">       <span class="p">|</span>                           <span class="p">|</span>
</span></span><span class="line"><span class="cl">       <span class="p">|</span> Send STREAM + FIN         <span class="p">|</span>
</span></span><span class="line"><span class="cl">       v                           v
</span></span><span class="line"><span class="cl">   +-------+                   +-------+
</span></span><span class="line"><span class="cl">   <span class="p">|</span> Data  <span class="p">|</span> Send RESET_STREAM <span class="p">|</span> Reset <span class="p">|</span>
</span></span><span class="line"><span class="cl">   <span class="p">|</span> Sent  <span class="p">|</span>------------------&gt;<span class="p">|</span> Sent  <span class="p">|</span>
</span></span><span class="line"><span class="cl">   +-------+                   +-------+
</span></span><span class="line"><span class="cl">       <span class="p">|</span>                           <span class="p">|</span>
</span></span><span class="line"><span class="cl">       <span class="p">|</span> Recv All ACKs             <span class="p">|</span> Recv ACK
</span></span><span class="line"><span class="cl">       v                           v
</span></span><span class="line"><span class="cl">   +-------+                   +-------+
</span></span><span class="line"><span class="cl">   <span class="p">|</span> Data  <span class="p">|</span>                   <span class="p">|</span> Reset <span class="p">|</span>
</span></span><span class="line"><span class="cl">   <span class="p">|</span> Recvd <span class="p">|</span>                   <span class="p">|</span> Recvd <span class="p">|</span>
</span></span><span class="line"><span class="cl">   +-------+                   +-------+
</span></span></code></pre></td></tr></table>
</div>
</div><h4 id="0x32接收流状态">0x32、接收流状态</h4>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span><span class="lnt">18
</span><span class="lnt">19
</span><span class="lnt">20
</span><span class="lnt">21
</span><span class="lnt">22
</span><span class="lnt">23
</span><span class="lnt">24
</span><span class="lnt">25
</span><span class="lnt">26
</span><span class="lnt">27
</span><span class="lnt">28
</span><span class="lnt">29
</span><span class="lnt">30
</span><span class="lnt">31
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">       o
</span></span><span class="line"><span class="cl">       <span class="p">|</span> Recv STREAM / STREAM_DATA_BLOCKED / RESET_STREAM
</span></span><span class="line"><span class="cl">       <span class="p">|</span> Create Bidirectional Stream <span class="o">(</span>Sending<span class="o">)</span>
</span></span><span class="line"><span class="cl">       <span class="p">|</span> Recv MAX_STREAM_DATA / STOP_SENDING <span class="o">(</span>Bidirectional<span class="o">)</span>
</span></span><span class="line"><span class="cl">       <span class="p">|</span> Create Higher-Numbered Stream
</span></span><span class="line"><span class="cl">       v
</span></span><span class="line"><span class="cl">   +-------+
</span></span><span class="line"><span class="cl">   <span class="p">|</span> Recv  <span class="p">|</span> Recv RESET_STREAM
</span></span><span class="line"><span class="cl">   <span class="p">|</span>       <span class="p">|</span>-----------------------.
</span></span><span class="line"><span class="cl">   +-------+                       <span class="p">|</span>
</span></span><span class="line"><span class="cl">       <span class="p">|</span>                           <span class="p">|</span>
</span></span><span class="line"><span class="cl">       <span class="p">|</span> Recv STREAM + FIN         <span class="p">|</span>
</span></span><span class="line"><span class="cl">       v                           <span class="p">|</span>
</span></span><span class="line"><span class="cl">   +-------+                       <span class="p">|</span>
</span></span><span class="line"><span class="cl">   <span class="p">|</span> Size  <span class="p">|</span> Recv RESET_STREAM     <span class="p">|</span>
</span></span><span class="line"><span class="cl">   <span class="p">|</span> Known <span class="p">|</span>----------------------&gt;<span class="p">|</span>
</span></span><span class="line"><span class="cl">   +-------+                       <span class="p">|</span>
</span></span><span class="line"><span class="cl">       <span class="p">|</span>                           <span class="p">|</span>
</span></span><span class="line"><span class="cl">       <span class="p">|</span> Recv All Data             <span class="p">|</span>
</span></span><span class="line"><span class="cl">       v                           v
</span></span><span class="line"><span class="cl">   +-------+ Recv RESET_STREAM +-------+
</span></span><span class="line"><span class="cl">   <span class="p">|</span> Data  <span class="p">|</span>--- <span class="o">(</span>optional<span class="o">)</span> ---&gt;<span class="p">|</span> Reset <span class="p">|</span>
</span></span><span class="line"><span class="cl">   <span class="p">|</span> Recvd <span class="p">|</span>  Recv All Data    <span class="p">|</span> Recvd <span class="p">|</span>
</span></span><span class="line"><span class="cl">   +-------+&lt;-- <span class="o">(</span>optional<span class="o">)</span> ----+-------+
</span></span><span class="line"><span class="cl">       <span class="p">|</span>                           <span class="p">|</span>
</span></span><span class="line"><span class="cl">       <span class="p">|</span> App Read All Data         <span class="p">|</span> App Read Reset
</span></span><span class="line"><span class="cl">       v                           v
</span></span><span class="line"><span class="cl">   +-------+                   +-------+
</span></span><span class="line"><span class="cl">   <span class="p">|</span> Data  <span class="p">|</span>                   <span class="p">|</span> Reset <span class="p">|</span>
</span></span><span class="line"><span class="cl">   <span class="p">|</span> Read  <span class="p">|</span>                   <span class="p">|</span> Read  <span class="p">|</span>
</span></span><span class="line"><span class="cl">   +-------+                   +-------+
</span></span></code></pre></td></tr></table>
</div>
</div><p>终端在收到<strong>最大流数据帧</strong>或<strong>停止发送帧</strong>后打开一条双向流。接收到一条未开启的流的<strong>最大流数据帧</strong>意味着对端已经开启了该流，并开始支持流量控制额度。而接收到一条未开启流的<strong>停止发送帧</strong>意味着对端不会再从该流接收数据。无论这两种帧的哪一种都可能先于<strong>流帧</strong>或<strong>流阻塞帧</strong>到达本端，原因是包丢失或乱序。</p>
<p>在一条流创建前，所有数值小于该流ID的同类型流都<em><strong>必须</strong></em>被创建。这样能确保双端流的创建次序保持一致。</p>
<p>在“接收”状态，终端接收<strong>流帧</strong>和<strong>流阻塞帧</strong>。传入数据将被缓存，并可以按照正确顺序重组以便递给应用层。随着应用层不断消耗数据，缓冲区重新空出来，终端发送<strong>最大流数据帧</strong>告知对端可以发送更多数据。</p>
<p>当收到一个带FIN置位的<strong>流帧</strong>时，数据的最终大小确定下来，详见第4.5章。流的接收部分随后转到“数据量确认”状态。在此状态，终端不再需要发送<strong>最大流数据帧</strong>，只需要接收重传数据即可。</p>
<p>一旦收完了一条流的所有数据，流的接收部分转入“接收完成”状态。这可能发生在收到导致转入“数据量确认”状态的同一个<strong>流帧</strong>后。在所有数据都收完后，可以丢弃该流的任何<strong>流帧</strong>或<strong>流阻塞帧</strong>。</p>
<h4 id="0x33permitted-frame-types">0x33、Permitted Frame Types</h4>
<p>流的发送端发送的帧只有三种能同时影响发送端和接收端状态：STREAM（第19.8章）、STREAM_DATA_BLOCKED（第19.13章），以及RESET_STREAM（第19.4章）。</p>
<p>流的接收端发送MAX_STREAM_DATA frames（第19.19章）及STOP_SENDING frames（第19.5章）。</p>
<h4 id="0x34双向流状态">0x34、双向流状态</h4>
<p>可能的对于HTTP2的状态映射 在最简单的模型里，当发送和接收部分均处在非最终状态时，表示流处于“打开”状态；当两者均处于最终状态时，表示流处于“关闭”状态。</p>
<p>Table 2: Possible Mapping of Stream States to HTTP/2</p>
<table>
<thead>
<tr>
<th align="left">Sending Part</th>
<th align="left">Receiving Part</th>
<th align="left">Composite State</th>
</tr>
</thead>
<tbody>
<tr>
<td align="left">No Stream / Ready</td>
<td align="left">No Stream / Recv (*1)</td>
<td align="left">idle</td>
</tr>
<tr>
<td align="left">Ready / Send / Data Sent</td>
<td align="left">Recv / Size Known</td>
<td align="left">open</td>
</tr>
<tr>
<td align="left">Ready / Send / Data Sent</td>
<td align="left">Data Recvd / Data Read</td>
<td align="left">half-closed (remote)</td>
</tr>
<tr>
<td align="left">Ready / Send / Data Sent</td>
<td align="left">Reset Recvd / Reset Read</td>
<td align="left">half-closed (remote)</td>
</tr>
<tr>
<td align="left">Data Recvd</td>
<td align="left">Recv / Size Known</td>
<td align="left">half-closed (local)</td>
</tr>
<tr>
<td align="left">Reset Sent / Reset Recvd</td>
<td align="left">Recv / Size Known</td>
<td align="left">half-closed (local)</td>
</tr>
<tr>
<td align="left">Reset Sent / Reset Recvd</td>
<td align="left">Data Recvd / Data Read</td>
<td align="left">closed</td>
</tr>
<tr>
<td align="left">Reset Sent / Reset Recvd</td>
<td align="left">Reset Recvd / Reset Read</td>
<td align="left">closed</td>
</tr>
<tr>
<td align="left">Data Recvd</td>
<td align="left">Data Recvd / Data Read</td>
<td align="left">closed</td>
</tr>
<tr>
<td align="left">Data Recvd</td>
<td align="left">Reset Recvd / Reset Read</td>
<td align="left">closed</td>
</tr>
</tbody>
</table>
<h4 id="0x35请求状态转换">0x35、请求状态转换</h4>
<p>A STOP_SENDING frame 请求接收方发送 a RESET_STREAM frame</p>
<p>如果双向流的一端想要将流的两个方向同时关闭，那么其可以通过发送一个RESET_STREAM关闭一个方向，并发送一个STOP_SENDING促使相反方向也迅速得到关闭。</p>
<h3 id="0x4流量控制">0x4、流量控制</h3>
<p>接收方需要限制缓存数据量以防发送方速度太快造成冲击或被恶意发送方消耗大量内存。为了让接收方能够限制连接的内存占用，不仅每条流有单独的流量控制，所有流也作为一个整体在连接层面有统一的流量控制。QUIC接收方控制发送方在一条流上以及任何时刻在所有流上可以发送的最大数据量，详见第4.1章或第4.2章。</p>
<p>同样地，为了限制连接并发，QUIC终端控制对方可以同时开启的最大流数量，详见第4.6章。</p>
<p>通过加密帧发送的数据不像流数据那样受流量控制制约。QUIC依赖于加密协议的实现来避免这些数据被过量缓存，详见《QUIC TLS》。为了防止在多个层次过量缓存数据，QUIC实现应该为加密协议实现提供一套接口以供其交流缓存区限制。</p>
<h4 id="0x41数据流量控制">0x41、数据流量控制</h4>
<p>QUIC使用一个基于限制的流量控制模型，接收者给出其准备在给定流或整个连接上准备接收的总字节数的上限。这使得QUIC中存在两层数据流量控制：</p>
<ul>
<li>流的流量控制：通过限制每条流可以发送的数据量，防止单条流耗尽一条连接的全部接收缓冲区；</li>
<li>连接流量控制：通过限制所有流经由<strong>流帧</strong>可以发送的数据量，防止发送方超过连接接收方的缓冲区容量。</li>
</ul>
<p>接收方在握手过程中（第7.4章）通过传输参数为所有流设置初始的流接收缓存区上限。随后，接收方发送最大流数据帧（第19.10章）或最大数据帧（第19.9章）以告知对方提高流接收缓存区上限。</p>
<p>如果发送方发送数据达到了流量控制上限，其将不能再发送新数据，且应认为其被阻塞住了。发送方应该发送一个流数据阻塞帧或数据阻塞帧来告知接收方其有数据要写出但是被流量控制所阻塞。如果发送方被阻塞的时间超过空等超时时间（第10.1章），接收方可以关闭连接，即便发送方有可传输的数据。为了保持连接不被关闭，在没有可引发ACK的数据包处于传输中时，被流量控制限制所阻塞的发送方应该定期发送一个流数据阻塞帧或数据阻塞帧。</p>
<h4 id="0x43流量控制性能">0x43、流量控制性能</h4>
<p>如果终端不能确保其对端始终在该连接上有大于对端带宽时延积的流量控制额度，其接收吞吐量将被流量控制限制。</p>
<p>包丢失会导致接收缓冲区出现空隙，从而阻碍应用层消耗数据并释放接收缓冲空间。</p>
<p>及时发送流量控制上限更新能提高性能。发送只包含流量控制更新的数据包会增加网络负载，对性能产生不利影响。将流量控制更新与其他帧一起发出，例如如ACK帧，可以降低此类更新带来的消耗。</p>
<h4 id="0x45流最终数据量">0x45、流最终数据量</h4>
<p>不管流是如何终止的，发送方始终试图将流的最终数据量可靠地发送给接收方。最终数据量是 带有FIN置位的流帧的Offset（下标）和Length（长度）字段值的总和，注意这些字段可能是隐式的。</p>
<h4 id="0x46并发控制">0x46、并发控制</h4>
<p>终端限制对端累计可以开启的流的数量。只有流ID小于(max_streams * 4 + first_stream_id_of_type)的流可以被开启，详见表1。初始限制由传输参数设置，详见第18.2章。随后的限制由最大流帧推出</p>
<p>max_streams不能超限$2^{60}$</p>
<h3 id="0x5-连接">0x5 连接</h3>
<h4 id="0x53-连接操作">0x53 连接操作</h4>
<p>当实现用户端时，应用层协议可以：</p>
<ul>
<li>创建一个连接，开始进行<a href="https://autumnquiche.github.io/RFC9000_Chinese_Translation/">第7章</a>描述的交互过程；</li>
<li>如果支持，启用早期数据功能；</li>
<li>当早期数据被服务端接受或拒绝时，收到通知。</li>
</ul>
<p>当实现服务端时，应用层协议可以：</p>
<ul>
<li>监听传入的连接，准备进行<a href="https://autumnquiche.github.io/RFC9000_Chinese_Translation/">第7章</a>描述的交互过程；</li>
<li>如果支持早期数据，在发送给客户端的TLS恢复ticket中嵌入应用层控制数据；</li>
<li>如果支持早期数据，从接收自客户端的恢复ticket中恢复应用层控制数据，并根据该信息接受或拒绝早期数据。</li>
</ul>
<p>当同时实现客户端及服务端时，应用层协议可以：</p>
<ul>
<li>如传输参数（[第7.4章]）所述，为每种类型允许的流的配置最小的初始数量；</li>
<li>通过设置流级别及连接级别的流量控制限制，限制接收缓存区资源分配；</li>
<li>识别握手已经成功结束抑或仍在进行中；</li>
<li>保持连接不被默认关闭，即通过PING帧（[第19.2章]）或其他请求使得传输层在空闲超时（[第10.1章]）前发送额外的帧；以及</li>
<li>立即关闭连接（[第10.2章]）。</li>
</ul>
<h3 id="0x7-加密与传输握手">0x7 加密与传输握手</h3>
<p>1-RTT example</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">Client                                                  Server
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">Initial<span class="o">[</span>0<span class="o">]</span>: CRYPTO<span class="o">[</span>CH<span class="o">]</span> -&gt;
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">                                 Initial<span class="o">[</span>0<span class="o">]</span>: CRYPTO<span class="o">[</span>SH<span class="o">]</span> ACK<span class="o">[</span>0<span class="o">]</span>
</span></span><span class="line"><span class="cl">                       Handshake<span class="o">[</span>0<span class="o">]</span>: CRYPTO<span class="o">[</span>EE, CERT, CV, FIN<span class="o">]</span>
</span></span><span class="line"><span class="cl">                                 &lt;- 1-RTT<span class="o">[</span>0<span class="o">]</span>: STREAM<span class="o">[</span>1, <span class="s2">&#34;...&#34;</span><span class="o">]</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">Initial<span class="o">[</span>1<span class="o">]</span>: ACK<span class="o">[</span>0<span class="o">]</span>
</span></span><span class="line"><span class="cl">Handshake<span class="o">[</span>0<span class="o">]</span>: CRYPTO<span class="o">[</span>FIN<span class="o">]</span>, ACK<span class="o">[</span>0<span class="o">]</span>
</span></span><span class="line"><span class="cl">1-RTT<span class="o">[</span>0<span class="o">]</span>: STREAM<span class="o">[</span>0, <span class="s2">&#34;...&#34;</span><span class="o">]</span>, ACK<span class="o">[</span>0<span class="o">]</span> -&gt;
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">                                          Handshake<span class="o">[</span>1<span class="o">]</span>: ACK<span class="o">[</span>0<span class="o">]</span>
</span></span><span class="line"><span class="cl">         &lt;- 1-RTT<span class="o">[</span>1<span class="o">]</span>: HANDSHAKE_DONE, STREAM<span class="o">[</span>3, <span class="s2">&#34;...&#34;</span><span class="o">]</span>, ACK<span class="o">[</span>0<span class="o">]</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>0-RTT example</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">Client                                                  Server
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">Initial<span class="o">[</span>0<span class="o">]</span>: CRYPTO<span class="o">[</span>CH<span class="o">]</span>
</span></span><span class="line"><span class="cl">0-RTT<span class="o">[</span>0<span class="o">]</span>: STREAM<span class="o">[</span>0, <span class="s2">&#34;...&#34;</span><span class="o">]</span> -&gt;
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">                                 Initial<span class="o">[</span>0<span class="o">]</span>: CRYPTO<span class="o">[</span>SH<span class="o">]</span> ACK<span class="o">[</span>0<span class="o">]</span>
</span></span><span class="line"><span class="cl">                                  Handshake<span class="o">[</span>0<span class="o">]</span> CRYPTO<span class="o">[</span>EE, FIN<span class="o">]</span>
</span></span><span class="line"><span class="cl">                          &lt;- 1-RTT<span class="o">[</span>0<span class="o">]</span>: STREAM<span class="o">[</span>1, <span class="s2">&#34;...&#34;</span><span class="o">]</span> ACK<span class="o">[</span>0<span class="o">]</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">Initial<span class="o">[</span>1<span class="o">]</span>: ACK<span class="o">[</span>0<span class="o">]</span>
</span></span><span class="line"><span class="cl">Handshake<span class="o">[</span>0<span class="o">]</span>: CRYPTO<span class="o">[</span>FIN<span class="o">]</span>, ACK<span class="o">[</span>0<span class="o">]</span>
</span></span><span class="line"><span class="cl">1-RTT<span class="o">[</span>1<span class="o">]</span>: STREAM<span class="o">[</span>0, <span class="s2">&#34;...&#34;</span><span class="o">]</span> ACK<span class="o">[</span>0<span class="o">]</span> -&gt;
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">                                          Handshake<span class="o">[</span>1<span class="o">]</span>: ACK<span class="o">[</span>0<span class="o">]</span>
</span></span><span class="line"><span class="cl">         &lt;- 1-RTT<span class="o">[</span>1<span class="o">]</span>: HANDSHAKE_DONE, STREAM<span class="o">[</span>3, <span class="s2">&#34;...&#34;</span><span class="o">]</span>, ACK<span class="o">[</span>1<span class="o">]</span>
</span></span></code></pre></td></tr></table>
</div>
</div><h3 id="0x12-packets-and-frames">0x12 Packets and Frames</h3>
<h4 id="0x124-frames-and-frame-types">0x124 Frames and Frame Types</h4>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="n">Packet</span> <span class="n">Payload</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="n">Frame</span> <span class="p">(</span><span class="mf">8.</span><span class="p">.)</span> <span class="p">...,</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>figure:QUIC payload</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="n">Frame</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="n">Frame</span> <span class="n">Type</span> <span class="p">(</span><span class="n">i</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">  <span class="n">Type</span><span class="o">-</span><span class="n">Dependent</span> <span class="n">Fields</span> <span class="p">(..),</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>figure:Generic Frame layout</p>
<table>
<thead>
<tr>
<th align="left">Type Value</th>
<th align="left">Frame Type Name</th>
<th align="left">Definition</th>
<th align="left">Pkts</th>
<th align="left">Spec</th>
</tr>
</thead>
<tbody>
<tr>
<td align="left">0x00</td>
<td align="left">PADDING</td>
<td align="left"><a href="https://www.rfc-editor.org/rfc/rfc9000.html#frame-padding">Section 19.1</a></td>
<td align="left">IH01</td>
<td align="left">NP</td>
</tr>
<tr>
<td align="left">0x01</td>
<td align="left">PING</td>
<td align="left"><a href="https://www.rfc-editor.org/rfc/rfc9000.html#frame-ping">Section 19.2</a></td>
<td align="left">IH01</td>
<td align="left"></td>
</tr>
<tr>
<td align="left">0x02-0x03</td>
<td align="left">ACK</td>
<td align="left"><a href="https://www.rfc-editor.org/rfc/rfc9000.html#frame-ack">Section 19.3</a></td>
<td align="left">IH_1</td>
<td align="left">NC</td>
</tr>
<tr>
<td align="left">0x04</td>
<td align="left">RESET_STREAM</td>
<td align="left"><a href="https://www.rfc-editor.org/rfc/rfc9000.html#frame-reset-stream">Section 19.4</a></td>
<td align="left">__01</td>
<td align="left"></td>
</tr>
<tr>
<td align="left">0x05</td>
<td align="left">STOP_SENDING</td>
<td align="left"><a href="https://www.rfc-editor.org/rfc/rfc9000.html#frame-stop-sending">Section 19.5</a></td>
<td align="left">__01</td>
<td align="left"></td>
</tr>
<tr>
<td align="left">0x06</td>
<td align="left">CRYPTO</td>
<td align="left"><a href="https://www.rfc-editor.org/rfc/rfc9000.html#frame-crypto">Section 19.6</a></td>
<td align="left">IH_1</td>
<td align="left"></td>
</tr>
<tr>
<td align="left">0x07</td>
<td align="left">NEW_TOKEN</td>
<td align="left"><a href="https://www.rfc-editor.org/rfc/rfc9000.html#frame-new-token">Section 19.7</a></td>
<td align="left">___1</td>
<td align="left"></td>
</tr>
<tr>
<td align="left">0x08-0x0f</td>
<td align="left">STREAM</td>
<td align="left"><a href="https://www.rfc-editor.org/rfc/rfc9000.html#frame-stream">Section 19.8</a></td>
<td align="left">__01</td>
<td align="left">F</td>
</tr>
<tr>
<td align="left">0x10</td>
<td align="left">MAX_DATA</td>
<td align="left"><a href="https://www.rfc-editor.org/rfc/rfc9000.html#frame-max-data">Section 19.9</a></td>
<td align="left">__01</td>
<td align="left"></td>
</tr>
<tr>
<td align="left">0x11</td>
<td align="left">MAX_STREAM_DATA</td>
<td align="left"><a href="https://www.rfc-editor.org/rfc/rfc9000.html#frame-max-stream-data">Section 19.10</a></td>
<td align="left">__01</td>
<td align="left"></td>
</tr>
<tr>
<td align="left">0x12-0x13</td>
<td align="left">MAX_STREAMS</td>
<td align="left"><a href="https://www.rfc-editor.org/rfc/rfc9000.html#frame-max-streams">Section 19.11</a></td>
<td align="left">__01</td>
<td align="left"></td>
</tr>
<tr>
<td align="left">0x14</td>
<td align="left">DATA_BLOCKED</td>
<td align="left"><a href="https://www.rfc-editor.org/rfc/rfc9000.html#frame-data-blocked">Section 19.12</a></td>
<td align="left">__01</td>
<td align="left"></td>
</tr>
<tr>
<td align="left">0x15</td>
<td align="left">STREAM_DATA_BLOCKED</td>
<td align="left"><a href="https://www.rfc-editor.org/rfc/rfc9000.html#frame-stream-data-blocked">Section 19.13</a></td>
<td align="left">__01</td>
<td align="left"></td>
</tr>
<tr>
<td align="left">0x16-0x17</td>
<td align="left">STREAMS_BLOCKED</td>
<td align="left"><a href="https://www.rfc-editor.org/rfc/rfc9000.html#frame-streams-blocked">Section 19.14</a></td>
<td align="left">__01</td>
<td align="left"></td>
</tr>
<tr>
<td align="left">0x18</td>
<td align="left">NEW_CONNECTION_ID</td>
<td align="left"><a href="https://www.rfc-editor.org/rfc/rfc9000.html#frame-new-connection-id">Section 19.15</a></td>
<td align="left">__01</td>
<td align="left">P</td>
</tr>
<tr>
<td align="left">0x19</td>
<td align="left">RETIRE_CONNECTION_ID</td>
<td align="left"><a href="https://www.rfc-editor.org/rfc/rfc9000.html#frame-retire-connection-id">Section 19.16</a></td>
<td align="left">__01</td>
<td align="left"></td>
</tr>
<tr>
<td align="left">0x1a</td>
<td align="left">PATH_CHALLENGE</td>
<td align="left"><a href="https://www.rfc-editor.org/rfc/rfc9000.html#frame-path-challenge">Section 19.17</a></td>
<td align="left">__01</td>
<td align="left">P</td>
</tr>
<tr>
<td align="left">0x1b</td>
<td align="left">PATH_RESPONSE</td>
<td align="left"><a href="https://www.rfc-editor.org/rfc/rfc9000.html#frame-path-response">Section 19.18</a></td>
<td align="left">___1</td>
<td align="left">P</td>
</tr>
<tr>
<td align="left">0x1c-0x1d</td>
<td align="left">CONNECTION_CLOSE</td>
<td align="left"><a href="https://www.rfc-editor.org/rfc/rfc9000.html#frame-connection-close">Section 19.19</a></td>
<td align="left">ih01</td>
<td align="left">N</td>
</tr>
<tr>
<td align="left">0x1e</td>
<td align="left">HANDSHAKE_DONE</td>
<td align="left"><a href="https://www.rfc-editor.org/rfc/rfc9000.html#frame-handshake-done">Section 19.20</a></td>
<td align="left">___1</td>
<td align="left"></td>
</tr>
</tbody>
</table>
<h3 id="0x16-可变长整型">0x16 可变长整型</h3>
<table>
<thead>
<tr>
<th align="left">最高的2个有效位</th>
<th align="left">字节长度</th>
<th align="left">可用位数</th>
<th align="left">可表示范围</th>
</tr>
</thead>
<tbody>
<tr>
<td align="left">00</td>
<td align="left">1</td>
<td align="left">6</td>
<td align="left">0-63</td>
</tr>
<tr>
<td align="left">01</td>
<td align="left">2</td>
<td align="left">14</td>
<td align="left">0-16383</td>
</tr>
<tr>
<td align="left">10</td>
<td align="left">4</td>
<td align="left">30</td>
<td align="left">0-1073741823</td>
</tr>
<tr>
<td align="left">11</td>
<td align="left">8</td>
<td align="left">62</td>
<td align="left">0-4611686018427387903</td>
</tr>
</tbody>
</table>
<h3 id="0x17-packet-formats">0x17 Packet Formats</h3>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="n">Long</span> <span class="n">Header</span> <span class="n">Packet</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="n">Header</span> <span class="n">Form</span> <span class="p">(</span><span class="mi">1</span><span class="p">)</span> <span class="o">=</span> <span class="mi">1</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="n">Fixed</span> <span class="n">Bit</span> <span class="p">(</span><span class="mi">1</span><span class="p">)</span> <span class="o">=</span> <span class="mi">1</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="n">Long</span> <span class="n">Packet</span> <span class="n">Type</span> <span class="p">(</span><span class="mi">2</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">  <span class="n">Type</span><span class="o">-</span><span class="n">Specific</span> <span class="n">Bits</span> <span class="p">(</span><span class="mi">4</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">  <span class="n">Version</span> <span class="p">(</span><span class="mi">32</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">  <span class="n">Destination</span> <span class="n">Connection</span> <span class="n">ID</span> <span class="n">Length</span> <span class="p">(</span><span class="mi">8</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">  <span class="n">Destination</span> <span class="n">Connection</span> <span class="n">ID</span> <span class="p">(</span><span class="mf">0..160</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">  <span class="n">Source</span> <span class="n">Connection</span> <span class="n">ID</span> <span class="n">Length</span> <span class="p">(</span><span class="mi">8</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">  <span class="n">Source</span> <span class="n">Connection</span> <span class="n">ID</span> <span class="p">(</span><span class="mf">0..160</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">  <span class="n">Type</span><span class="o">-</span><span class="n">Specific</span> <span class="n">Payload</span> <span class="p">(..),</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>Long Packet Type</p>
<table>
<thead>
<tr>
<th align="left">类型</th>
<th align="left">名称</th>
<th align="left">章节</th>
</tr>
</thead>
<tbody>
<tr>
<td align="left">0x00</td>
<td align="left">初始</td>
<td align="left">[第17.2.2章]</td>
</tr>
<tr>
<td align="left">0x01</td>
<td align="left">0-RTT</td>
<td align="left">[第17.2.3章]</td>
</tr>
<tr>
<td align="left">0x02</td>
<td align="left">握手</td>
<td align="left">[第17.2.4章]</td>
</tr>
<tr>
<td align="left">0x03</td>
<td align="left">重试</td>
<td align="left">[第17.2.5章]</td>
</tr>
</tbody>
</table>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span><span class="lnt">18
</span><span class="lnt">19
</span><span class="lnt">20
</span><span class="lnt">21
</span><span class="lnt">22
</span><span class="lnt">23
</span><span class="lnt">24
</span><span class="lnt">25
</span><span class="lnt">26
</span><span class="lnt">27
</span><span class="lnt">28
</span><span class="lnt">29
</span><span class="lnt">30
</span><span class="lnt">31
</span><span class="lnt">32
</span><span class="lnt">33
</span><span class="lnt">34
</span><span class="lnt">35
</span><span class="lnt">36
</span><span class="lnt">37
</span><span class="lnt">38
</span><span class="lnt">39
</span><span class="lnt">40
</span><span class="lnt">41
</span><span class="lnt">42
</span><span class="lnt">43
</span><span class="lnt">44
</span><span class="lnt">45
</span><span class="lnt">46
</span><span class="lnt">47
</span><span class="lnt">48
</span><span class="lnt">49
</span><span class="lnt">50
</span><span class="lnt">51
</span><span class="lnt">52
</span><span class="lnt">53
</span><span class="lnt">54
</span><span class="lnt">55
</span><span class="lnt">56
</span><span class="lnt">57
</span><span class="lnt">58
</span><span class="lnt">59
</span><span class="lnt">60
</span><span class="lnt">61
</span><span class="lnt">62
</span><span class="lnt">63
</span><span class="lnt">64
</span><span class="lnt">65
</span><span class="lnt">66
</span><span class="lnt">67
</span><span class="lnt">68
</span><span class="lnt">69
</span><span class="lnt">70
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="n">Version</span> <span class="n">Negotiation</span> <span class="n">Packet</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="n">Header</span> <span class="n">Form</span> <span class="p">(</span><span class="mi">1</span><span class="p">)</span> <span class="o">=</span> <span class="mi">1</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="n">Unused</span> <span class="p">(</span><span class="mi">7</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">  <span class="n">Version</span> <span class="p">(</span><span class="mi">32</span><span class="p">)</span> <span class="o">=</span> <span class="mi">0</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="n">Destination</span> <span class="n">Connection</span> <span class="n">ID</span> <span class="n">Length</span> <span class="p">(</span><span class="mi">8</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">  <span class="n">Destination</span> <span class="n">Connection</span> <span class="n">ID</span> <span class="p">(</span><span class="mf">0..2040</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">  <span class="n">Source</span> <span class="n">Connection</span> <span class="n">ID</span> <span class="n">Length</span> <span class="p">(</span><span class="mi">8</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">  <span class="n">Source</span> <span class="n">Connection</span> <span class="n">ID</span> <span class="p">(</span><span class="mf">0..2040</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">  <span class="n">Supported</span> <span class="n">Version</span> <span class="p">(</span><span class="mi">32</span><span class="p">)</span> <span class="p">...,</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="n">Initial</span> <span class="n">Packet</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="n">Header</span> <span class="n">Form</span> <span class="p">(</span><span class="mi">1</span><span class="p">)</span> <span class="o">=</span> <span class="mi">1</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="n">Fixed</span> <span class="n">Bit</span> <span class="p">(</span><span class="mi">1</span><span class="p">)</span> <span class="o">=</span> <span class="mi">1</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="n">Long</span> <span class="n">Packet</span> <span class="n">Type</span> <span class="p">(</span><span class="mi">2</span><span class="p">)</span> <span class="o">=</span> <span class="mi">0</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="n">Reserved</span> <span class="n">Bits</span> <span class="p">(</span><span class="mi">2</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">  <span class="n">Packet</span> <span class="n">Number</span> <span class="n">Length</span> <span class="p">(</span><span class="mi">2</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">  <span class="n">Version</span> <span class="p">(</span><span class="mi">32</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">  <span class="n">Destination</span> <span class="n">Connection</span> <span class="n">ID</span> <span class="n">Length</span> <span class="p">(</span><span class="mi">8</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">  <span class="n">Destination</span> <span class="n">Connection</span> <span class="n">ID</span> <span class="p">(</span><span class="mf">0..160</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">  <span class="n">Source</span> <span class="n">Connection</span> <span class="n">ID</span> <span class="n">Length</span> <span class="p">(</span><span class="mi">8</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">  <span class="n">Source</span> <span class="n">Connection</span> <span class="n">ID</span> <span class="p">(</span><span class="mf">0..160</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">  <span class="n">Token</span> <span class="n">Length</span> <span class="p">(</span><span class="n">i</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">  <span class="n">Token</span> <span class="p">(..),</span>
</span></span><span class="line"><span class="cl">  <span class="n">Length</span> <span class="p">(</span><span class="n">i</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">  <span class="n">Packet</span> <span class="n">Number</span> <span class="p">(</span><span class="mf">8..32</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">  <span class="n">Packet</span> <span class="n">Payload</span> <span class="p">(</span><span class="mf">8.</span><span class="p">.),</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="mi">0</span><span class="o">-</span><span class="n">RTT</span> <span class="n">Packet</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="n">Header</span> <span class="n">Form</span> <span class="p">(</span><span class="mi">1</span><span class="p">)</span> <span class="o">=</span> <span class="mi">1</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="n">Fixed</span> <span class="n">Bit</span> <span class="p">(</span><span class="mi">1</span><span class="p">)</span> <span class="o">=</span> <span class="mi">1</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="n">Long</span> <span class="n">Packet</span> <span class="n">Type</span> <span class="p">(</span><span class="mi">2</span><span class="p">)</span> <span class="o">=</span> <span class="mi">1</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="n">Reserved</span> <span class="n">Bits</span> <span class="p">(</span><span class="mi">2</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">  <span class="n">Packet</span> <span class="n">Number</span> <span class="n">Length</span> <span class="p">(</span><span class="mi">2</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">  <span class="n">Version</span> <span class="p">(</span><span class="mi">32</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">  <span class="n">Destination</span> <span class="n">Connection</span> <span class="n">ID</span> <span class="n">Length</span> <span class="p">(</span><span class="mi">8</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">  <span class="n">Destination</span> <span class="n">Connection</span> <span class="n">ID</span> <span class="p">(</span><span class="mf">0..160</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">  <span class="n">Source</span> <span class="n">Connection</span> <span class="n">ID</span> <span class="n">Length</span> <span class="p">(</span><span class="mi">8</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">  <span class="n">Source</span> <span class="n">Connection</span> <span class="n">ID</span> <span class="p">(</span><span class="mf">0..160</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">  <span class="n">Length</span> <span class="p">(</span><span class="n">i</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">  <span class="n">Packet</span> <span class="n">Number</span> <span class="p">(</span><span class="mf">8..32</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">  <span class="n">Packet</span> <span class="n">Payload</span> <span class="p">(</span><span class="mf">8.</span><span class="p">.),</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="n">Handshake</span> <span class="n">Packet</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="n">Header</span> <span class="n">Form</span> <span class="p">(</span><span class="mi">1</span><span class="p">)</span> <span class="o">=</span> <span class="mi">1</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="n">Fixed</span> <span class="n">Bit</span> <span class="p">(</span><span class="mi">1</span><span class="p">)</span> <span class="o">=</span> <span class="mi">1</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="n">Long</span> <span class="n">Packet</span> <span class="n">Type</span> <span class="p">(</span><span class="mi">2</span><span class="p">)</span> <span class="o">=</span> <span class="mi">2</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="n">Reserved</span> <span class="n">Bits</span> <span class="p">(</span><span class="mi">2</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">  <span class="n">Packet</span> <span class="n">Number</span> <span class="n">Length</span> <span class="p">(</span><span class="mi">2</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">  <span class="n">Version</span> <span class="p">(</span><span class="mi">32</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">  <span class="n">Destination</span> <span class="n">Connection</span> <span class="n">ID</span> <span class="n">Length</span> <span class="p">(</span><span class="mi">8</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">  <span class="n">Destination</span> <span class="n">Connection</span> <span class="n">ID</span> <span class="p">(</span><span class="mf">0..160</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">  <span class="n">Source</span> <span class="n">Connection</span> <span class="n">ID</span> <span class="n">Length</span> <span class="p">(</span><span class="mi">8</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">  <span class="n">Source</span> <span class="n">Connection</span> <span class="n">ID</span> <span class="p">(</span><span class="mf">0..160</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">  <span class="n">Length</span> <span class="p">(</span><span class="n">i</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">  <span class="n">Packet</span> <span class="n">Number</span> <span class="p">(</span><span class="mf">8..32</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">  <span class="n">Packet</span> <span class="n">Payload</span> <span class="p">(</span><span class="mf">8.</span><span class="p">.),</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="n">Retry</span> <span class="n">Packet</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="n">Header</span> <span class="n">Form</span> <span class="p">(</span><span class="mi">1</span><span class="p">)</span> <span class="o">=</span> <span class="mi">1</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="n">Fixed</span> <span class="n">Bit</span> <span class="p">(</span><span class="mi">1</span><span class="p">)</span> <span class="o">=</span> <span class="mi">1</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="n">Long</span> <span class="n">Packet</span> <span class="n">Type</span> <span class="p">(</span><span class="mi">2</span><span class="p">)</span> <span class="o">=</span> <span class="mi">3</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="n">Unused</span> <span class="p">(</span><span class="mi">4</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">  <span class="n">Version</span> <span class="p">(</span><span class="mi">32</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">  <span class="n">Destination</span> <span class="n">Connection</span> <span class="n">ID</span> <span class="n">Length</span> <span class="p">(</span><span class="mi">8</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">  <span class="n">Destination</span> <span class="n">Connection</span> <span class="n">ID</span> <span class="p">(</span><span class="mf">0..160</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">  <span class="n">Source</span> <span class="n">Connection</span> <span class="n">ID</span> <span class="n">Length</span> <span class="p">(</span><span class="mi">8</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">  <span class="n">Source</span> <span class="n">Connection</span> <span class="n">ID</span> <span class="p">(</span><span class="mf">0..160</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">  <span class="n">Retry</span> <span class="n">Token</span> <span class="p">(..),</span>
</span></span><span class="line"><span class="cl">  <span class="n">Retry</span> <span class="n">Integrity</span> <span class="n">Tag</span> <span class="p">(</span><span class="mi">128</span><span class="p">),</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></td></tr></table>
</div>
</div><div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="mi">1</span><span class="o">-</span><span class="n">RTT</span> <span class="n">Packet</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="n">Header</span> <span class="n">Form</span> <span class="p">(</span><span class="mi">1</span><span class="p">)</span> <span class="o">=</span> <span class="mi">0</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="n">Fixed</span> <span class="n">Bit</span> <span class="p">(</span><span class="mi">1</span><span class="p">)</span> <span class="o">=</span> <span class="mi">1</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="n">Spin</span> <span class="n">Bit</span> <span class="p">(</span><span class="mi">1</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">  <span class="n">Reserved</span> <span class="n">Bits</span> <span class="p">(</span><span class="mi">2</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">  <span class="n">Key</span> <span class="n">Phase</span> <span class="p">(</span><span class="mi">1</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">  <span class="n">Packet</span> <span class="n">Number</span> <span class="n">Length</span> <span class="p">(</span><span class="mi">2</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">  <span class="n">Destination</span> <span class="n">Connection</span> <span class="n">ID</span> <span class="p">(</span><span class="mf">0..160</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">  <span class="n">Packet</span> <span class="n">Number</span> <span class="p">(</span><span class="mf">8..32</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">  <span class="n">Packet</span> <span class="n">Payload</span> <span class="p">(</span><span class="mf">8.</span><span class="p">.),</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></td></tr></table>
</div>
</div><h3 id="0x18-传输参数编码">0x18 传输参数编码</h3>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span><span class="lnt">6
</span><span class="lnt">7
</span><span class="lnt">8
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="n">Transport</span> <span class="n">Parameters</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="n">Transport</span> <span class="n">Parameter</span> <span class="p">(..)</span> <span class="p">...,</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="n">Transport</span> <span class="n">Parameter</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="n">Transport</span> <span class="n">Parameter</span> <span class="n">ID</span> <span class="p">(</span><span class="n">i</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">  <span class="n">Transport</span> <span class="n">Parameter</span> <span class="n">Length</span> <span class="p">(</span><span class="n">i</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">  <span class="n">Transport</span> <span class="n">Parameter</span> <span class="n">Value</span> <span class="p">(..),</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></td></tr></table>
</div>
</div><h3 id="0x19-帧类型和格式">0x19 帧类型和格式</h3>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">  1
</span><span class="lnt">  2
</span><span class="lnt">  3
</span><span class="lnt">  4
</span><span class="lnt">  5
</span><span class="lnt">  6
</span><span class="lnt">  7
</span><span class="lnt">  8
</span><span class="lnt">  9
</span><span class="lnt"> 10
</span><span class="lnt"> 11
</span><span class="lnt"> 12
</span><span class="lnt"> 13
</span><span class="lnt"> 14
</span><span class="lnt"> 15
</span><span class="lnt"> 16
</span><span class="lnt"> 17
</span><span class="lnt"> 18
</span><span class="lnt"> 19
</span><span class="lnt"> 20
</span><span class="lnt"> 21
</span><span class="lnt"> 22
</span><span class="lnt"> 23
</span><span class="lnt"> 24
</span><span class="lnt"> 25
</span><span class="lnt"> 26
</span><span class="lnt"> 27
</span><span class="lnt"> 28
</span><span class="lnt"> 29
</span><span class="lnt"> 30
</span><span class="lnt"> 31
</span><span class="lnt"> 32
</span><span class="lnt"> 33
</span><span class="lnt"> 34
</span><span class="lnt"> 35
</span><span class="lnt"> 36
</span><span class="lnt"> 37
</span><span class="lnt"> 38
</span><span class="lnt"> 39
</span><span class="lnt"> 40
</span><span class="lnt"> 41
</span><span class="lnt"> 42
</span><span class="lnt"> 43
</span><span class="lnt"> 44
</span><span class="lnt"> 45
</span><span class="lnt"> 46
</span><span class="lnt"> 47
</span><span class="lnt"> 48
</span><span class="lnt"> 49
</span><span class="lnt"> 50
</span><span class="lnt"> 51
</span><span class="lnt"> 52
</span><span class="lnt"> 53
</span><span class="lnt"> 54
</span><span class="lnt"> 55
</span><span class="lnt"> 56
</span><span class="lnt"> 57
</span><span class="lnt"> 58
</span><span class="lnt"> 59
</span><span class="lnt"> 60
</span><span class="lnt"> 61
</span><span class="lnt"> 62
</span><span class="lnt"> 63
</span><span class="lnt"> 64
</span><span class="lnt"> 65
</span><span class="lnt"> 66
</span><span class="lnt"> 67
</span><span class="lnt"> 68
</span><span class="lnt"> 69
</span><span class="lnt"> 70
</span><span class="lnt"> 71
</span><span class="lnt"> 72
</span><span class="lnt"> 73
</span><span class="lnt"> 74
</span><span class="lnt"> 75
</span><span class="lnt"> 76
</span><span class="lnt"> 77
</span><span class="lnt"> 78
</span><span class="lnt"> 79
</span><span class="lnt"> 80
</span><span class="lnt"> 81
</span><span class="lnt"> 82
</span><span class="lnt"> 83
</span><span class="lnt"> 84
</span><span class="lnt"> 85
</span><span class="lnt"> 86
</span><span class="lnt"> 87
</span><span class="lnt"> 88
</span><span class="lnt"> 89
</span><span class="lnt"> 90
</span><span class="lnt"> 91
</span><span class="lnt"> 92
</span><span class="lnt"> 93
</span><span class="lnt"> 94
</span><span class="lnt"> 95
</span><span class="lnt"> 96
</span><span class="lnt"> 97
</span><span class="lnt"> 98
</span><span class="lnt"> 99
</span><span class="lnt">100
</span><span class="lnt">101
</span><span class="lnt">102
</span><span class="lnt">103
</span><span class="lnt">104
</span><span class="lnt">105
</span><span class="lnt">106
</span><span class="lnt">107
</span><span class="lnt">108
</span><span class="lnt">109
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="n">PADDING</span> <span class="n">Frame</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="n">Type</span> <span class="p">(</span><span class="n">i</span><span class="p">)</span> <span class="o">=</span> <span class="mh">0x00</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="n">PING</span> <span class="n">Frame</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="n">Type</span> <span class="p">(</span><span class="n">i</span><span class="p">)</span> <span class="o">=</span> <span class="mh">0x01</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="n">ACK</span> <span class="n">Frame</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="n">Type</span> <span class="p">(</span><span class="n">i</span><span class="p">)</span> <span class="o">=</span> <span class="mh">0x02</span><span class="p">.</span><span class="mf">.0</span><span class="n">x03</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="n">Largest</span> <span class="n">Acknowledged</span> <span class="p">(</span><span class="n">i</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">  <span class="n">ACK</span> <span class="n">Delay</span> <span class="p">(</span><span class="n">i</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">  <span class="n">ACK</span> <span class="n">Range</span> <span class="n">Count</span> <span class="p">(</span><span class="n">i</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">  <span class="n">First</span> <span class="n">ACK</span> <span class="n">Range</span> <span class="p">(</span><span class="n">i</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">  <span class="n">ACK</span> <span class="n">Range</span> <span class="p">(..)</span> <span class="p">...,</span>
</span></span><span class="line"><span class="cl">  <span class="p">[</span><span class="n">ECN</span> <span class="n">Counts</span> <span class="p">(..)],</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="n">ACK</span> <span class="n">Range</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="n">Gap</span> <span class="p">(</span><span class="n">i</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">  <span class="n">ACK</span> <span class="n">Range</span> <span class="n">Length</span> <span class="p">(</span><span class="n">i</span><span class="p">),</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="n">ECN</span> <span class="n">Counts</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="n">ECT0</span> <span class="n">Count</span> <span class="p">(</span><span class="n">i</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">  <span class="n">ECT1</span> <span class="n">Count</span> <span class="p">(</span><span class="n">i</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">  <span class="n">ECN</span><span class="o">-</span><span class="n">CE</span> <span class="n">Count</span> <span class="p">(</span><span class="n">i</span><span class="p">),</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="n">RESET_STREAM</span> <span class="n">Frame</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="n">Type</span> <span class="p">(</span><span class="n">i</span><span class="p">)</span> <span class="o">=</span> <span class="mh">0x04</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="n">Stream</span> <span class="n">ID</span> <span class="p">(</span><span class="n">i</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">  <span class="n">Application</span> <span class="n">Protocol</span> <span class="n">Error</span> <span class="n">Code</span> <span class="p">(</span><span class="n">i</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">  <span class="n">Final</span> <span class="n">Size</span> <span class="p">(</span><span class="n">i</span><span class="p">),</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="n">STOP_SENDING</span> <span class="n">Frame</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="n">Type</span> <span class="p">(</span><span class="n">i</span><span class="p">)</span> <span class="o">=</span> <span class="mh">0x05</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="n">Stream</span> <span class="n">ID</span> <span class="p">(</span><span class="n">i</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">  <span class="n">Application</span> <span class="n">Protocol</span> <span class="n">Error</span> <span class="n">Code</span> <span class="p">(</span><span class="n">i</span><span class="p">),</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="n">CRYPTO</span> <span class="n">Frame</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="n">Type</span> <span class="p">(</span><span class="n">i</span><span class="p">)</span> <span class="o">=</span> <span class="mh">0x06</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="n">Offset</span> <span class="p">(</span><span class="n">i</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">  <span class="n">Length</span> <span class="p">(</span><span class="n">i</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">  <span class="n">Crypto</span> <span class="n">Data</span> <span class="p">(..),</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="n">NEW_TOKEN</span> <span class="n">Frame</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="n">Type</span> <span class="p">(</span><span class="n">i</span><span class="p">)</span> <span class="o">=</span> <span class="mh">0x07</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="n">Token</span> <span class="n">Length</span> <span class="p">(</span><span class="n">i</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">  <span class="n">Token</span> <span class="p">(..),</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="n">STREAM</span> <span class="n">Frame</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="n">Type</span> <span class="p">(</span><span class="n">i</span><span class="p">)</span> <span class="o">=</span> <span class="mh">0x08</span><span class="p">.</span><span class="mf">.0</span><span class="n">x0f</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="n">Stream</span> <span class="n">ID</span> <span class="p">(</span><span class="n">i</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">  <span class="p">[</span><span class="n">Offset</span> <span class="p">(</span><span class="n">i</span><span class="p">)],</span>
</span></span><span class="line"><span class="cl">  <span class="p">[</span><span class="n">Length</span> <span class="p">(</span><span class="n">i</span><span class="p">)],</span>
</span></span><span class="line"><span class="cl">  <span class="n">Stream</span> <span class="n">Data</span> <span class="p">(..),</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="n">MAX_DATA</span> <span class="n">Frame</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="n">Type</span> <span class="p">(</span><span class="n">i</span><span class="p">)</span> <span class="o">=</span> <span class="mh">0x10</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="n">Maximum</span> <span class="n">Data</span> <span class="p">(</span><span class="n">i</span><span class="p">),</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="n">MAX_STREAM_DATA</span> <span class="n">Frame</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="n">Type</span> <span class="p">(</span><span class="n">i</span><span class="p">)</span> <span class="o">=</span> <span class="mh">0x11</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="n">Stream</span> <span class="n">ID</span> <span class="p">(</span><span class="n">i</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">  <span class="n">Maximum</span> <span class="n">Stream</span> <span class="n">Data</span> <span class="p">(</span><span class="n">i</span><span class="p">),</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="n">MAX_STREAMS</span> <span class="n">Frame</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="n">Type</span> <span class="p">(</span><span class="n">i</span><span class="p">)</span> <span class="o">=</span> <span class="mh">0x12</span><span class="p">.</span><span class="mf">.0</span><span class="n">x13</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="n">Maximum</span> <span class="n">Streams</span> <span class="p">(</span><span class="n">i</span><span class="p">),</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="n">DATA_BLOCKED</span> <span class="n">Frame</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="n">Type</span> <span class="p">(</span><span class="n">i</span><span class="p">)</span> <span class="o">=</span> <span class="mh">0x14</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="n">Maximum</span> <span class="n">Data</span> <span class="p">(</span><span class="n">i</span><span class="p">),</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="n">STREAM_DATA_BLOCKED</span> <span class="n">Frame</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="n">Type</span> <span class="p">(</span><span class="n">i</span><span class="p">)</span> <span class="o">=</span> <span class="mh">0x15</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="n">Stream</span> <span class="n">ID</span> <span class="p">(</span><span class="n">i</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">  <span class="n">Maximum</span> <span class="n">Stream</span> <span class="n">Data</span> <span class="p">(</span><span class="n">i</span><span class="p">),</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="n">STREAMS_BLOCKED</span> <span class="n">Frame</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="n">Type</span> <span class="p">(</span><span class="n">i</span><span class="p">)</span> <span class="o">=</span> <span class="mh">0x16</span><span class="p">.</span><span class="mf">.0</span><span class="n">x17</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="n">Maximum</span> <span class="n">Streams</span> <span class="p">(</span><span class="n">i</span><span class="p">),</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="n">NEW_CONNECTION_ID</span> <span class="n">Frame</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="n">Type</span> <span class="p">(</span><span class="n">i</span><span class="p">)</span> <span class="o">=</span> <span class="mh">0x18</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="n">Sequence</span> <span class="n">Number</span> <span class="p">(</span><span class="n">i</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">  <span class="n">Retire</span> <span class="n">Prior</span> <span class="n">To</span> <span class="p">(</span><span class="n">i</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">  <span class="n">Length</span> <span class="p">(</span><span class="mi">8</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">  <span class="n">Connection</span> <span class="n">ID</span> <span class="p">(</span><span class="mf">8..160</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">  <span class="n">Stateless</span> <span class="n">Reset</span> <span class="n">Token</span> <span class="p">(</span><span class="mi">128</span><span class="p">),</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="n">RETIRE_CONNECTION_ID</span> <span class="n">Frame</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="n">Type</span> <span class="p">(</span><span class="n">i</span><span class="p">)</span> <span class="o">=</span> <span class="mh">0x19</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="n">Sequence</span> <span class="n">Number</span> <span class="p">(</span><span class="n">i</span><span class="p">),</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="n">PATH_CHALLENGE</span> <span class="n">Frame</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="n">Type</span> <span class="p">(</span><span class="n">i</span><span class="p">)</span> <span class="o">=</span> <span class="mh">0x1a</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="n">Data</span> <span class="p">(</span><span class="mi">64</span><span class="p">),</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="n">PATH_RESPONSE</span> <span class="n">Frame</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="n">Type</span> <span class="p">(</span><span class="n">i</span><span class="p">)</span> <span class="o">=</span> <span class="mh">0x1b</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="n">Data</span> <span class="p">(</span><span class="mi">64</span><span class="p">),</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="n">CONNECTION_CLOSE</span> <span class="n">Frame</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="n">Type</span> <span class="p">(</span><span class="n">i</span><span class="p">)</span> <span class="o">=</span> <span class="mh">0x1c</span><span class="p">.</span><span class="mf">.0</span><span class="n">x1d</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="n">Error</span> <span class="n">Code</span> <span class="p">(</span><span class="n">i</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">  <span class="p">[</span><span class="n">Frame</span> <span class="n">Type</span> <span class="p">(</span><span class="n">i</span><span class="p">)],</span>
</span></span><span class="line"><span class="cl">  <span class="n">Reason</span> <span class="n">Phrase</span> <span class="n">Length</span> <span class="p">(</span><span class="n">i</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">  <span class="n">Reason</span> <span class="n">Phrase</span> <span class="p">(..),</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="n">HANDSHAKE_DONE</span> <span class="n">Frame</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="n">Type</span> <span class="p">(</span><span class="n">i</span><span class="p">)</span> <span class="o">=</span> <span class="mh">0x1e</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></td></tr></table>
</div>
</div><h2 id="rfc9114">RFC9114</h2>
<p>HTTP/1.1直接使用空格和crlf来分割传递数据，虽然可读性高但是网络利用率不高，多个请求使用对个TCP连接并行请求还会加重拥塞。</p>
<p>HTTP/2引入了binary framing和multiplexing layer，在不修改传输层的清苦那个下改善延迟。然而，HTTP/2的多路复用并行性质对TCP的丢失机制是不可见的(TCP向上提供透明服务)，一个丢失或者重新排序的数据包会导致所有的活动事务经历一个暂停，而不管该事务是否直接收到丢失数据包的影响。</p>
<p>QUIC协议合并了stream multiplexing和per-stream control，通过提供流级别的可靠性和整个连接的拥塞控制，提高HTTP性能。QUIC在传输层合并了TLS 1.3提供HTTPS的机密性和完整性，改进了TCP Fast Open的连接设置延迟。</p>
<p>QUIC提供了协议协商、基于流的多路复用和流控制。HTTP/3请求的多路复用是使用QUIC抽象流来执行的，每个请求响应对消耗单一的QUIC流，流之间相互独立，一个流的阻塞和抛弃不会影响其他流。</p>
<p>每个流中，HTTP/3通信的基本单元式frame。每个frame都有不同的用途，例如<code>HEADERS</code>和<code>DATA</code> frame构成了HTTP请求和相应的基础。</p>
<p>server push是HTTP/2中引入的交互模式,允许server在client发出指定请求前想clent推送一个request-respose exchange。几个HTTP/3 frame被用来管理server push，如<code>PUSH_PROMISE</code>、<code>MAX_PUSH_ID</code>和<code>CANCEL_PUSH</code>.</p>
<p>文档组织</p>
<ul>
<li>第三章介绍了如何发现HTTP/3断点和如何建立连接</li>
<li>第四章描述如何使用frame来表达HTTP语义</li>
<li>第五章描述了HTTP/3连接时如何被优雅或者突然地停止的</li>
<li>第六章描述了使用QUIC流的方式</li>
<li>第七章描述了大多数流上使用的帧</li>
</ul>
<h3 id="第三章连接设置和管理">第三章、连接设置和管理</h3>
<p><code>发现HTTP/3 endpoint</code></p>
<p>client访问https的uri资源，解析成IP地址，在指定端口建立QUIC连接，通过安全连接向server发送HTTP/3请求。连接问题(阻塞UDP)可能导致无法建立QUIC连接，这种情况client尝试基于tcp版本的HTTP</p>
<p>可以通过HTTP相应头字段告知端口支持HTTP/3协议</p>
<pre tabindex="0"><code>Alt-Svc: h3=&#34;:50781&#34;
</code></pre><p>接收到Alt-Svc响应client尝试建立QUIC连接</p>
<p><code>连接建立</code></p>
<p>QUIC建立连接，使用TLS1.3以上进行握手，握手中通过选择APLN令牌h3表示HTTP/3支持，其他应用层协议的支持可以在相同握手中提供。QUIC核心协议相关选项在初始加密握手设置时，HTTP3的设置传入到<code>SETTINGS</code> frame。QUIC连接建立后，<code>SETTINGS</code> frame必须被每个端点作为HTTP控制流的初始frame发送。</p>
<p><code>连接复用</code></p>
<p>为了使用一个现有的连接到一个新的源，客户端必须验证服务器为新的源服务器提供的证书，这意味着客户端需要保留服务器证书和验证该证书需要的任何额外信息，不这样做的客户端将无法为其其他来源重用连接。</p>
<h3 id="第四章在http3中表达http语义">第四章、在HTTP3中表达HTTP语义</h3>
<p>一个HTTP消息包括</p>
<ul>
<li>
<ol>
<li>header，sent as single HEADERS frame</li>
</ol>
</li>
<li>
<ol start="2">
<li>Optional content，sent as a series of DATA frames</li>
</ol>
</li>
<li>
<ol start="3">
<li>Optional tailer section, sent as a single HEADERS frame</li>
</ol>
</li>
</ul>
<p>接收到无效的帧序列作为  <code>H3_FRAME_UNEXPECTED</code> 类型的连接错误，如DATA在HEADERS前</p>
<p>服务端可以在响应消息交错推送<code>PUSH_PROMISE</code>帧，包含<code>PUSH_PROMISE</code>帧的推送响应必然被视为<code>H3_FRAME_UNEXPECTED</code>类型的错误连接</p>
<p>HTTP请求响应完全消费双向QUIC流，当client发送请求后必须关闭发送流，客户端绝对不能让流关闭依赖于接收到对其请求的响应，在发送最终响应后，服务端必须关闭发送流。这时，QUIC流完全关闭。</p>
<p>如果客户端发起流在没有提供足够HTTP message以供响应而终止，server abort错误码<code>H3_REQUEST_INCOMPLETE</code></p>
<p><code>H3_REQUEST_REJECTED</code> vs <code>H3_REQUEST_CANCELLED</code></p>
<p>server不能使用REJECTED处理部分响应请求</p>
<p>完整响应被取消可以使用 部分响应被取消不能使用 幂等请求可安全重试</p>
<p>畸形请求以<code>H3_MESSAGE_ERROE</code>的流错误处理</p>
<p><code>HTTP Fields</code></p>
<p>QPACK(HTTP3)描述了HPACK(HTTP2)的变体,压缩包头和尾部部分，包括出现在报头部分的控制数据。为了获得更好的压缩效率，Cookies字段可能被分成多个fields line，如果解压缩的字段包含多个cookie字段，这些行必须以<code>; </code>(0x3b 0x20)分割</p>
<p>server收到header过大可以发送一个HTTP 431状态码</p>
<p><code>HTTP Control Data</code></p>
<p>伪报头以<code>:</code>（0x3a）开头 携带控制数据，请求伪报头不能出现在响应中 反之亦然，伪报头不能出现在尾部部分</p>
<p>所有HTTP/3请求必须包含 <code>:method</code>, <code>:scheme</code>, and <code>:path</code> 伪首部</p>
<p>响应是 <code>:status</code> 伪报头 携带状态码</p>
<p>HTTP3不支持HTTP升级机制</p>
<p><code>Server Push</code></p>
<p>推送ID从0开始，通过<code>MAX_PUSH_ID</code> frame控制服务器可以承诺的最大推送ID</p>
<p>ID用于一个或多个<code>PUSH_PROMISE</code>frames 携带控制数据和报头字段，这些frames发送到生成push的request stream，这允许server push和client请求关联，当相同的pushID被承诺在不同的request streams中时，解压后的request field必须包含相同的同顺序fields，键值也必须相同。然后pushID被包含在最终实现这些promise的push steam中，push stream识别他实现的pushID然后包含promised request对应的response</p>
<p>reordering，数据可能在<code>PUSH_PROMISE</code>前到达，客户端缓冲数据等待匹配。</p>
<h3 id="第六章stream-mapping-and-usage">第六章、Stream Mapping and Usage</h3>
<p>QUIC stream提供可靠的按序bytes，传输层对接收到的流数据进行缓冲和排序，向应用程序expose一个可靠的字节流。QUIC流可以是双向的也可以是单向的，可以由客户端发起也可以由服务端发起。HTTP使用QUIC发送数据，QUIC层处理大部分流管理，HTTP不需要做任何单独的多路复用处理，通过QUIC流发送的数据总是映射到一个特定的HTTP事务或整个HTTP3连接上下文。</p>
<h4 id="双向流">双向流</h4>
<p>所有客户端发起的双向流都用于HTTP请求和响应。双向流确保响应可以很容易地与请求相关联。这些流被称为请求流。<br />
这意味着客户端第一个请求发生在QUIC流 0上，随后的请求发生在流4、流8上，以此类推。为了允许这些流打开，HTTP/3服务器应该为允许的流的数量和初始流的流量控制窗口配置非零的最小值。为了减少并行度限制，一次至少应该允许100个请求流。</p>
<h4 id="单向流">单向流</h4>
<p>任何一个单向流都可以用于不同的用于，用途由流类型表示，在流的开头以变长整数形式发送，这个整数后面的数据格式和结构由流类型决定。</p>
<p>单向流header:</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="n">Unidirectional</span> <span class="n">Stream</span> <span class="n">Header</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="n">Stream</span> <span class="n">Type</span> <span class="p">(</span><span class="n">i</span><span class="p">),</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>本文档定义了控制流和push流，每个端点需要为HTTP控制流创建至少一个单向流，QPACK需要两个额外的单向流，因此server client发送的传输参数必须允许对等端创建至少三个单项流。</p>
<p><code>Control Streams</code></p>
<p>控制流由0x00表示，该流上的数据由HTTP3 frames组成</p>
<p>每一方必须在连接开始时启动一个控制流，并将其<code>SETTINGS</code> frame作为第一个frame发送</p>
<p><code>Push Streams</code></p>
<p>推送流由0x01表示，后面跟着他锁实现的承诺的push ID，编码为边长整型，该流剩余数据又HTTP3 frames组成</p>
<p>push stream header:</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="n">Push</span> <span class="n">Stream</span> <span class="n">Header</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="n">Stream</span> <span class="n">Type</span> <span class="p">(</span><span class="n">i</span><span class="p">)</span> <span class="o">=</span> <span class="mh">0x01</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="n">Push</span> <span class="n">ID</span> <span class="p">(</span><span class="n">i</span><span class="p">),</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p><code>Reserved Stream Types</code></p>
<h3 id="第七章http-framing-layer">第七章、HTTP Framing Layer</h3>
<p>下表表示HTTP3 frames和他们允许的流类型</p>
<table>
<thead>
<tr>
<th align="left">Frame</th>
<th align="left">Control Stream</th>
<th align="left">Request Stream</th>
<th align="left">Push Stream</th>
<th align="left">Section</th>
</tr>
</thead>
<tbody>
<tr>
<td align="left"><a href="https://www.rfc-editor.org/rfc/rfc9114.html#frame-data">DATA</a></td>
<td align="left">No</td>
<td align="left">Yes</td>
<td align="left">Yes</td>
<td align="left"><a href="https://www.rfc-editor.org/rfc/rfc9114.html#frame-data">Section 7.2.1</a></td>
</tr>
<tr>
<td align="left"><a href="https://www.rfc-editor.org/rfc/rfc9114.html#frame-headers">HEADERS</a></td>
<td align="left">No</td>
<td align="left">Yes</td>
<td align="left">Yes</td>
<td align="left"><a href="https://www.rfc-editor.org/rfc/rfc9114.html#frame-headers">Section 7.2.2</a></td>
</tr>
<tr>
<td align="left"><a href="https://www.rfc-editor.org/rfc/rfc9114.html#frame-cancel-push">CANCEL_PUSH</a></td>
<td align="left">Yes</td>
<td align="left">No</td>
<td align="left">No</td>
<td align="left"><a href="https://www.rfc-editor.org/rfc/rfc9114.html#frame-cancel-push">Section 7.2.3</a></td>
</tr>
<tr>
<td align="left"><a href="https://www.rfc-editor.org/rfc/rfc9114.html#frame-settings">SETTINGS</a></td>
<td align="left">Yes (1)</td>
<td align="left">No</td>
<td align="left">No</td>
<td align="left"><a href="https://www.rfc-editor.org/rfc/rfc9114.html#frame-settings">Section 7.2.4</a></td>
</tr>
<tr>
<td align="left"><a href="https://www.rfc-editor.org/rfc/rfc9114.html#frame-push-promise">PUSH_PROMISE</a></td>
<td align="left">No</td>
<td align="left">Yes</td>
<td align="left">No</td>
<td align="left"><a href="https://www.rfc-editor.org/rfc/rfc9114.html#frame-push-promise">Section 7.2.5</a></td>
</tr>
<tr>
<td align="left"><a href="https://www.rfc-editor.org/rfc/rfc9114.html#frame-goaway">GOAWAY</a></td>
<td align="left">Yes</td>
<td align="left">No</td>
<td align="left">No</td>
<td align="left"><a href="https://www.rfc-editor.org/rfc/rfc9114.html#frame-goaway">Section 7.2.6</a></td>
</tr>
<tr>
<td align="left"><a href="https://www.rfc-editor.org/rfc/rfc9114.html#frame-max-push-id">MAX_PUSH_ID</a></td>
<td align="left">Yes</td>
<td align="left">No</td>
<td align="left">No</td>
<td align="left"><a href="https://www.rfc-editor.org/rfc/rfc9114.html#frame-max-push-id">Section 7.2.7</a></td>
</tr>
<tr>
<td align="left">Reserved</td>
<td align="left">Yes</td>
<td align="left">Yes</td>
<td align="left">Yes</td>
<td align="left"><a href="https://www.rfc-editor.org/rfc/rfc9114.html#frame-reserved">Section 7.2.8</a></td>
</tr>
</tbody>
</table>
<h4 id="frame-layout">Frame Layout</h4>
<p>所有的frame有下面的格式</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="n">HTTP</span><span class="o">/</span><span class="mi">3</span> <span class="n">Frame</span> <span class="n">Format</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="n">Type</span> <span class="p">(</span><span class="n">i</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">  <span class="n">Length</span> <span class="p">(</span><span class="n">i</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">  <span class="n">Frame</span> <span class="n">Payload</span> <span class="p">(..),</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>Type:变长整数表示frames类型</p>
<p>Length:边长整数表示frames长度</p>
<p>Frame Payload:数据</p>
<h4 id="frame-definitions">Frame Definitions</h4>
<p><code>DATA</code></p>
<p>DATA frame 0x00 可变长字节序列</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="n">DATA</span> <span class="n">Frame</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="n">Type</span> <span class="p">(</span><span class="n">i</span><span class="p">)</span> <span class="o">=</span> <span class="mh">0x00</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="n">Length</span> <span class="p">(</span><span class="n">i</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">  <span class="n">Data</span> <span class="p">(..),</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p><code>HEADERS</code></p>
<p>headers 0x01 用于携带QPACK编码的HTTP fields</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="n">HEADERS</span> <span class="n">Frame</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="n">Type</span> <span class="p">(</span><span class="n">i</span><span class="p">)</span> <span class="o">=</span> <span class="mh">0x01</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="n">Length</span> <span class="p">(</span><span class="n">i</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">  <span class="n">Encoded</span> <span class="n">Field</span> <span class="n">Section</span> <span class="p">(..),</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>headers frame 只能在请求流或者push stream中发送</p>
<p><code>CANCEL_PUSH</code></p>
<p>cancel_push 0x03 用来在接收到推送流之前取消server push</p>
<p>client发送表示不想要</p>
<p>server发送表示不会履行承诺</p>
<p>携带一个push ID，标识被取消的server push</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="n">CANCEL_PUSH</span> <span class="n">Frame</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="n">Type</span> <span class="p">(</span><span class="n">i</span><span class="p">)</span> <span class="o">=</span> <span class="mh">0x03</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="n">Length</span> <span class="p">(</span><span class="n">i</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">  <span class="n">Push</span> <span class="n">ID</span> <span class="p">(</span><span class="n">i</span><span class="p">),</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p><code>Settings</code></p>
<p>settings 0x04 传递配置参数 比如对等行为的偏好和约束，应用于整个HTTP3连接而不是整个流</p>
<p>settings frame只能在control stream上发送</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="n">Setting</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="n">Identifier</span> <span class="p">(</span><span class="n">i</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">  <span class="n">Value</span> <span class="p">(</span><span class="n">i</span><span class="p">),</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">SETTINGS</span> <span class="n">Frame</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="n">Type</span> <span class="p">(</span><span class="n">i</span><span class="p">)</span> <span class="o">=</span> <span class="mh">0x04</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="n">Length</span> <span class="p">(</span><span class="n">i</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">  <span class="n">Setting</span> <span class="p">(..)</span> <span class="p">...,</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>忽略所有不理解的标识符参数</p>
<p><code>PUSH_PROMISE</code></p>
<p>push_promise 0x05 用于在请求流中携带从服务器到客户端的被承诺的请求报头片段</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span><span class="lnt">6
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="n">PUSH_PROMISE</span> <span class="n">Frame</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="n">Type</span> <span class="p">(</span><span class="n">i</span><span class="p">)</span> <span class="o">=</span> <span class="mh">0x05</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="n">Length</span> <span class="p">(</span><span class="n">i</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">  <span class="n">Push</span> <span class="n">ID</span> <span class="p">(</span><span class="n">i</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">  <span class="n">Encoded</span> <span class="n">Field</span> <span class="n">Section</span> <span class="p">(..),</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>encoded field section被承诺响应的QPACK请求报头字段</p>
<p>客户端绝对不能发送PUSH_PROMISE frame</p>
<p><code>GOAWAY</code></p>
<p>GOAWAY frame 0x07 用于启动HTTP3连接的任意断点的优雅关闭</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="n">GOAWAY</span> <span class="n">Frame</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="n">Type</span> <span class="p">(</span><span class="n">i</span><span class="p">)</span> <span class="o">=</span> <span class="mh">0x07</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="n">Length</span> <span class="p">(</span><span class="n">i</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">  <span class="n">Stream</span> <span class="n">ID</span><span class="o">/</span><span class="n">Push</span> <span class="n">ID</span> <span class="p">(</span><span class="n">i</span><span class="p">),</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>只能在控制流上传输，应用于整个连接</p>
<p><code>MAX_PUSH_ID</code></p>
<p>max_push_id 0x0d 被客户端用来控制服务器可以发起的服务器推送数量。</p>
<p>只能在控制流上发送，server不能发送，server在收到MAX_PUSH_ID前不能推送，frame携带一个边长整数用来标识server可以使用的推送ID最大值。</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="n">MAX_PUSH_ID</span> <span class="n">Frame</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="n">Type</span> <span class="p">(</span><span class="n">i</span><span class="p">)</span> <span class="o">=</span> <span class="mh">0x0d</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="n">Length</span> <span class="p">(</span><span class="n">i</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">  <span class="n">Push</span> <span class="n">ID</span> <span class="p">(</span><span class="n">i</span><span class="p">),</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p><code>Reserved Frame Types</code></p>
<h2 id="rfc9204">RFC9204</h2>
<p>可以在quic-go源码中看到其handleConn中第一步就是<code>qpack.NewDecoder(nil)</code>创建一个qpack decoder</p>
<p>其使用的库是&quot;github.com/marten-seemann/qpack&quot;,而qpack也是RFC9204规定的HTTP/3的字段压缩方式</p>
<h3 id="abstract">Abstract</h3>
<p>该规范定义了 QPACK：一种用于有效表示将在 HTTP/3 中使用的 HTTP 字段的压缩格式。这是 HPACK 压缩的一种变体，旨在减少行头阻塞(HOL blocking)</p>
<h3 id="2压缩过程概述">2、压缩过程概述</h3>
<p>与HPACK相似，QPACK使用两个表(第三章的Static table和Dynamic table)将字段行(“头”)与索引相关联。<code>Static table</code>是预定义的，包含常见的头字段行(其中一些是空值)。<code>Dynamic table</code>动态表是在连接过程中建立的，<code>Encoder</code>编码器可以使用它来索引编码字段段中的头字段行和尾字段行。</p>
<p>QPACK定义了单向流，用于将指令从编码器发送到解码器，反之亦然。</p>
<h4 id="21encoder">2.1、Encoder</h4>
<p>编码器通过为列表中的每个字段行发出索引或文字表示，将头部或尾部部分转换为一系列表示;参见4.5节。索引表示通过用静态或动态表的索引替换文字名称和可能的值来实现高压缩。对静态表和文字表示的引用不需要任何动态状态，而且永远不会有行首阻塞的风险。如果编码器没有收到表示该条目在解码器中是可用的确认信息，则引用动态表可能会导致行首阻塞</p>
<p>编码器可以在它选择的动态表中插入任何条目，不局限于他在压缩的字段行。</p>
<p>QPACK保留了每个字段部分中字段行的顺序。编码器必须按照字段在输入字段部分中出现的顺序发出字段表示。</p>
<p>QPACK的设计目的是将可选状态跟踪的负担放在编码器上，从而产生相对简单的解码器</p>
<p><code>2.1.1.动态表插入的限制</code></p>
<p><code>2.1.2.阻塞流</code></p>
<p><code>2.1.3.避免流控制死锁</code></p>
<p><code>2.1.4.已知接收计数</code></p>
<p>已知接收计数是解码器确认的动态表插入和重复的总数。编码器跟踪已知的接收计数，以便识别哪些动态表条目可以被引用，而不会潜在地阻塞流。解码器跟踪已知的接收计数，以便能够发送插入计数增量指令。<br />
Acknowledgment指令(章节4.4.1)意味着解码器已经收到了解码字段Section所需的所有动态表状态。如果确认字段部分的“所需插入计数”大于当前的“已知接收计数”，则“已知接收计数”将更新为“所需插入计数”值。(Known Received Count/Required Insert Count)<br />
插入计数递增指令(第4.4.3节)通过其递增参数递增已知接收计数。</p>
<h4 id="22decoder">2.2、Decoder</h4>
<p>与HPACK一样，解码器处理一系列表示并发出相应的字段部分。它还处理从编码器流接收到的修改动态表的指令。请注意，编码字段部分和编码器流指令在不同的流上到达。这与HPACK不同，在HPACK中，编码字段部分(头块)可以包含修改动态表的指令，并且没有HPACK指令的专用流。</p>
<p>解码器必须按字段表示在编码字段部分中出现的顺序发出字段行。</p>
<p><code>2.2.1.阻塞解码</code></p>
<p><code>2.2.2.状态同步</code></p>
<p><code>2.2.3.无效参考</code></p>
<h3 id="3reference-tables">3、Reference Tables</h3>
<p>与HPACK不同，QPACK静态表和动态表中的条目是分别寻址的。下面的部分描述了每个表中的条目是如何寻址的</p>
<h4 id="31static-table">3.1、Static Table</h4>
<p>静态表由预定义的字段行列表组成，每条字段行都有一个随时间变化的固定索引。</p>
<p>静态表中的所有条目都有一个名称和一个值。但是，值可以为空(即长度为0)。每个条目由唯一的索引标识</p>
<p>QPACK从0开始索引 HPACK从1开始索引</p>
<h4 id="32dynamic-table">3.2、Dynamic Table</h4>
<p>动态表由一个以先进先出的顺序维护的字段行列表组成。QPACK编码器和解码器共享一个最初为空的动态表。编码器将条目添加到动态表中，并通过编码器流上的指令将它们发送给解码器</p>
<p>可以有重复条目，表项可以有空值。</p>
<p><code>3.2.1. Dynamic Table Size</code></p>
<p>size = len(name) + len(value) + 32</p>
<p><code>3.2.2. Dynamic Table Capacity and Eviction</code></p>
<p>编码器设置动态表的容量作为其最大值 初始容量为0 编码器发送一个具有非零值的Set Dynamic Table Capacity指令开始使用动态表。</p>
<p>大小不够插入就移出一个表项</p>
<p>新条目可以引用之前的表项，要注意移出的时候避免移出被引用表项。</p>
<p><code>3.2.3. Maximum Dynamic Table Capacity</code></p>
<p>约束解码器内存需求，解码器限制编码器允许为动态表容量设置的最大值。由解码器发送的SETTING_QPACK_MAX_TABLE_CAPACITY决定，编码器不能设置超过这个最大值。</p>
<p><code>3.2.4. Absolute Indexing</code></p>
<p>每个条目都拥有一个绝对索引，该索引在条目的生命周期内是固定的。插入的第一个条目的绝对索引为0;每插入一次，索引就增加1</p>
<p><code>3.2.5. Relative Indexing</code></p>
<p>相对索引从零开始，向与绝对指数相反的方向增长。确定哪个条目的相对索引为0取决于引用的上下文</p>
<p>在编码器指令(章节4.3)中，0的相对索引指的是动态表中最近插入的值。注意，这意味着在解释编码器流上的指令时，给定相对索引引用的条目将发生变化。</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">      +-----+---------------+-------+
</span></span><span class="line"><span class="cl">      <span class="p">|</span> n-1 <span class="p">|</span>      ...      <span class="p">|</span>   d   <span class="p">|</span>  Absolute Index
</span></span><span class="line"><span class="cl">      + - - +---------------+ - - - +
</span></span><span class="line"><span class="cl">      <span class="p">|</span>  <span class="m">0</span>  <span class="p">|</span>      ...      <span class="p">|</span> n-d-1 <span class="p">|</span>  Relative Index
</span></span><span class="line"><span class="cl">      +-----+---------------+-------+
</span></span><span class="line"><span class="cl">      ^                             <span class="p">|</span>
</span></span><span class="line"><span class="cl">      <span class="p">|</span>                             V
</span></span><span class="line"><span class="cl">Insertion Point               Dropping Point
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nv">n</span> <span class="o">=</span> count of entries inserted
</span></span><span class="line"><span class="cl"><span class="nv">d</span> <span class="o">=</span> count of entries dropped
</span></span></code></pre></td></tr></table>
</div>
</div><p>动态表索引-编码器流</p>
<p>与编码器指令不同的是，字段行表示中的相对索引相对于被编码的字段行开头的Base;看到4.5.1节。这确保了即使编码字段部分和动态表更新被乱序处理，引用也是稳定的</p>
<p>在字段行表示中，相对索引为0指的是绝对索引等于Base - 1的条目</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">               Base
</span></span><span class="line"><span class="cl">                <span class="p">|</span>
</span></span><span class="line"><span class="cl">                V
</span></span><span class="line"><span class="cl">    +-----+-----+-----+-----+-------+
</span></span><span class="line"><span class="cl">    <span class="p">|</span> n-1 <span class="p">|</span> n-2 <span class="p">|</span> n-3 <span class="p">|</span> ... <span class="p">|</span>   d   <span class="p">|</span>  Absolute Index
</span></span><span class="line"><span class="cl">    +-----+-----+  -  +-----+   -   +
</span></span><span class="line"><span class="cl">                <span class="p">|</span>  <span class="m">0</span>  <span class="p">|</span> ... <span class="p">|</span> n-d-3 <span class="p">|</span>  Relative Index
</span></span><span class="line"><span class="cl">                +-----+-----+-------+
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nv">n</span> <span class="o">=</span> count of entries inserted
</span></span><span class="line"><span class="cl"><span class="nv">d</span> <span class="o">=</span> count of entries dropped
</span></span><span class="line"><span class="cl">In this example, <span class="nv">Base</span> <span class="o">=</span> n - <span class="m">2</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>动态表索引示例-表示中的相对索引</p>
<p><code>3.2.6. Post-Base Indexing</code></p>
<h3 id="4wire-format">4、Wire Format</h3>
<h4 id="42-encoder-and-decoder-streams">4.2. Encoder and Decoder Streams</h4>
<p>QPACK定义了两个单项流</p>
<ul>
<li>0x02 encoder stream carries an unframed sequence of encoder instructions</li>
<li>0x03 decoder stream carries an unframed sequence of decoder instructions</li>
</ul>
<p>每个端点必须也仅能启动一个encoder stream和decoder stream</p>
<h4 id="43-encoder-指令">4.3. Encoder 指令</h4>
<p><code>4.3.1. 设置Dynamic table capacity</code></p>
<p>001开头</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">  <span class="m">0</span>   <span class="m">1</span>   <span class="m">2</span>   <span class="m">3</span>   <span class="m">4</span>   <span class="m">5</span>   <span class="m">6</span>   <span class="m">7</span>
</span></span><span class="line"><span class="cl">+---+---+---+---+---+---+---+---+
</span></span><span class="line"><span class="cl"><span class="p">|</span> <span class="m">0</span> <span class="p">|</span> <span class="m">0</span> <span class="p">|</span> <span class="m">1</span> <span class="p">|</span>   Capacity <span class="o">(</span>5+<span class="o">)</span>   <span class="p">|</span>
</span></span><span class="line"><span class="cl">+---+---+---+-------------------+
</span></span></code></pre></td></tr></table>
</div>
</div><p><code>4.3.2. Insert with Name Reference</code></p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span><span class="lnt">6
</span><span class="lnt">7
</span><span class="lnt">8
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">     <span class="m">0</span>   <span class="m">1</span>   <span class="m">2</span>   <span class="m">3</span>   <span class="m">4</span>   <span class="m">5</span>   <span class="m">6</span>   <span class="m">7</span>
</span></span><span class="line"><span class="cl">   +---+---+---+---+---+---+---+---+
</span></span><span class="line"><span class="cl">   <span class="p">|</span> <span class="m">1</span> <span class="p">|</span> T <span class="p">|</span>    Name Index <span class="o">(</span>6+<span class="o">)</span>    <span class="p">|</span>
</span></span><span class="line"><span class="cl">   +---+---+-----------------------+
</span></span><span class="line"><span class="cl">   <span class="p">|</span> H <span class="p">|</span>     Value Length <span class="o">(</span>7+<span class="o">)</span>     <span class="p">|</span>
</span></span><span class="line"><span class="cl">   +---+---------------------------+
</span></span><span class="line"><span class="cl">   <span class="p">|</span>  Value String <span class="o">(</span>Length bytes<span class="o">)</span>  <span class="p">|</span>
</span></span><span class="line"><span class="cl">   +-------------------------------+
</span></span></code></pre></td></tr></table>
</div>
</div><p>插入字段行 Indexed name</p>
<p><code>4.3.3. Insert with Literal Name</code></p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">     <span class="m">0</span>   <span class="m">1</span>   <span class="m">2</span>   <span class="m">3</span>   <span class="m">4</span>   <span class="m">5</span>   <span class="m">6</span>   <span class="m">7</span>
</span></span><span class="line"><span class="cl">   +---+---+---+---+---+---+---+---+
</span></span><span class="line"><span class="cl">   <span class="p">|</span> <span class="m">0</span> <span class="p">|</span> <span class="m">1</span> <span class="p">|</span> H <span class="p">|</span> Name Length <span class="o">(</span>5+<span class="o">)</span>  <span class="p">|</span>
</span></span><span class="line"><span class="cl">   +---+---+---+-------------------+
</span></span><span class="line"><span class="cl">   <span class="p">|</span>  Name String <span class="o">(</span>Length bytes<span class="o">)</span>   <span class="p">|</span>
</span></span><span class="line"><span class="cl">   +---+---------------------------+
</span></span><span class="line"><span class="cl">   <span class="p">|</span> H <span class="p">|</span>     Value Length <span class="o">(</span>7+<span class="o">)</span>     <span class="p">|</span>
</span></span><span class="line"><span class="cl">   +---+---------------------------+
</span></span><span class="line"><span class="cl">   <span class="p">|</span>  Value String <span class="o">(</span>Length bytes<span class="o">)</span>  <span class="p">|</span>
</span></span><span class="line"><span class="cl">   +-------------------------------+
</span></span></code></pre></td></tr></table>
</div>
</div><p>插入字段行 New name</p>
<p><code>4.3.4. Duplicate</code></p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">     <span class="m">0</span>   <span class="m">1</span>   <span class="m">2</span>   <span class="m">3</span>   <span class="m">4</span>   <span class="m">5</span>   <span class="m">6</span>   <span class="m">7</span>
</span></span><span class="line"><span class="cl">   +---+---+---+---+---+---+---+---+
</span></span><span class="line"><span class="cl">   <span class="p">|</span> <span class="m">0</span> <span class="p">|</span> <span class="m">0</span> <span class="p">|</span> <span class="m">0</span> <span class="p">|</span>    Index <span class="o">(</span>5+<span class="o">)</span>     <span class="p">|</span>
</span></span><span class="line"><span class="cl">   +---+---+---+-------------------+
</span></span></code></pre></td></tr></table>
</div>
</div><p>重复</p>
<h4 id="44-decoder-指令">4.4. Decoder 指令</h4>
<p><code>4.4.1. Section Acknowledgment</code></p>
<p>在处理了一个Required Insert Count不为0的编码字段时回复ACK</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">  <span class="m">0</span>   <span class="m">1</span>   <span class="m">2</span>   <span class="m">3</span>   <span class="m">4</span>   <span class="m">5</span>   <span class="m">6</span>   <span class="m">7</span>
</span></span><span class="line"><span class="cl">+---+---+---+---+---+---+---+---+
</span></span><span class="line"><span class="cl"><span class="p">|</span> <span class="m">1</span> <span class="p">|</span>      Stream ID <span class="o">(</span>7+<span class="o">)</span>       <span class="p">|</span>
</span></span><span class="line"><span class="cl">+---+---------------------------+
</span></span></code></pre></td></tr></table>
</div>
</div><p><code>4.4.2. Stream Cancellation</code></p>
<p>当流被重置或放弃读取时，发送取消指令</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">  <span class="m">0</span>   <span class="m">1</span>   <span class="m">2</span>   <span class="m">3</span>   <span class="m">4</span>   <span class="m">5</span>   <span class="m">6</span>   <span class="m">7</span>
</span></span><span class="line"><span class="cl">+---+---+---+---+---+---+---+---+
</span></span><span class="line"><span class="cl"><span class="p">|</span> <span class="m">0</span> <span class="p">|</span> <span class="m">1</span> <span class="p">|</span>     Stream ID <span class="o">(</span>6+<span class="o">)</span>    <span class="p">|</span>
</span></span><span class="line"><span class="cl">+---+---+-----------------------+
</span></span></code></pre></td></tr></table>
</div>
</div><p><code>4.4.3. Insert Count Increment</code></p>
<p>该指令通过Increment参数的值增加已知接收计数(章节2.1.4)。解码器应该发送一个Increment值，将已知接收计数增加到到目前为止处理的动态表插入和重复的总数</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">  <span class="m">0</span>   <span class="m">1</span>   <span class="m">2</span>   <span class="m">3</span>   <span class="m">4</span>   <span class="m">5</span>   <span class="m">6</span>   <span class="m">7</span>
</span></span><span class="line"><span class="cl">+---+---+---+---+---+---+---+---+
</span></span><span class="line"><span class="cl"><span class="p">|</span> <span class="m">0</span> <span class="p">|</span> <span class="m">0</span> <span class="p">|</span>     Increment <span class="o">(</span>6+<span class="o">)</span>    <span class="p">|</span>
</span></span><span class="line"><span class="cl">+---+---+-----------------------+
</span></span></code></pre></td></tr></table>
</div>
</div><h4 id="45--field-line-representations">4.5.  Field Line Representations</h4>
<p><code>4.5.1. Encoded Field Section Prefix</code></p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span><span class="lnt">6
</span><span class="lnt">7
</span><span class="lnt">8
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">  <span class="m">0</span>   <span class="m">1</span>   <span class="m">2</span>   <span class="m">3</span>   <span class="m">4</span>   <span class="m">5</span>   <span class="m">6</span>   <span class="m">7</span>
</span></span><span class="line"><span class="cl">+---+---+---+---+---+---+---+---+
</span></span><span class="line"><span class="cl"><span class="p">|</span>   Required Insert Count <span class="o">(</span>8+<span class="o">)</span>  <span class="p">|</span>
</span></span><span class="line"><span class="cl">+---+---------------------------+
</span></span><span class="line"><span class="cl"><span class="p">|</span> S <span class="p">|</span>      Delta Base <span class="o">(</span>7+<span class="o">)</span>      <span class="p">|</span>
</span></span><span class="line"><span class="cl">+---+---------------------------+
</span></span><span class="line"><span class="cl"><span class="p">|</span>      Encoded Field Lines    ...
</span></span><span class="line"><span class="cl">+-------------------------------+
</span></span></code></pre></td></tr></table>
</div>
</div><p><code>4.5.1.1. Required Insert Count</code></p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">   <span class="k">if</span> <span class="nv">ReqInsertCount</span> <span class="o">==</span> 0:
</span></span><span class="line"><span class="cl">      <span class="nv">EncInsertCount</span> <span class="o">=</span> <span class="m">0</span>
</span></span><span class="line"><span class="cl">   <span class="k">else</span>:
</span></span><span class="line"><span class="cl">      <span class="nv">EncInsertCount</span> <span class="o">=</span> <span class="o">(</span>ReqInsertCount mod <span class="o">(</span><span class="m">2</span> * MaxEntries<span class="o">))</span> + <span class="m">1</span>
</span></span></code></pre></td></tr></table>
</div>
</div><div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">   <span class="nv">MaxEntries</span> <span class="o">=</span> floor<span class="o">(</span> MaxTableCapacity / <span class="m">32</span> <span class="o">)</span>
</span></span></code></pre></td></tr></table>
</div>
</div><div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span><span class="lnt">18
</span><span class="lnt">19
</span><span class="lnt">20
</span><span class="lnt">21
</span><span class="lnt">22
</span><span class="lnt">23
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">   <span class="nv">FullRange</span> <span class="o">=</span> <span class="m">2</span> * MaxEntries
</span></span><span class="line"><span class="cl">   <span class="k">if</span> <span class="nv">EncodedInsertCount</span> <span class="o">==</span> 0:
</span></span><span class="line"><span class="cl">      <span class="nv">ReqInsertCount</span> <span class="o">=</span> <span class="m">0</span>
</span></span><span class="line"><span class="cl">   <span class="k">else</span>:
</span></span><span class="line"><span class="cl">      <span class="k">if</span> EncodedInsertCount &gt; FullRange:
</span></span><span class="line"><span class="cl">         Error
</span></span><span class="line"><span class="cl">      <span class="nv">MaxValue</span> <span class="o">=</span> TotalNumberOfInserts + MaxEntries
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">      <span class="c1"># MaxWrapped is the largest possible value of</span>
</span></span><span class="line"><span class="cl">      <span class="c1"># ReqInsertCount that is 0 mod 2 * MaxEntries</span>
</span></span><span class="line"><span class="cl">      <span class="nv">MaxWrapped</span> <span class="o">=</span> floor<span class="o">(</span>MaxValue / FullRange<span class="o">)</span> * FullRange
</span></span><span class="line"><span class="cl">      <span class="nv">ReqInsertCount</span> <span class="o">=</span> MaxWrapped + EncodedInsertCount - <span class="m">1</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">      <span class="c1"># If ReqInsertCount exceeds MaxValue, the Encoder&#39;s value</span>
</span></span><span class="line"><span class="cl">      <span class="c1"># must have wrapped one fewer time</span>
</span></span><span class="line"><span class="cl">      <span class="k">if</span> ReqInsertCount &gt; MaxValue:
</span></span><span class="line"><span class="cl">         <span class="k">if</span> ReqInsertCount &lt;<span class="o">=</span> FullRange:
</span></span><span class="line"><span class="cl">            Error
</span></span><span class="line"><span class="cl">         ReqInsertCount -<span class="o">=</span> FullRange
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">      <span class="c1"># Value of 0 must be encoded as 0.</span>
</span></span><span class="line"><span class="cl">      <span class="k">if</span> <span class="nv">ReqInsertCount</span> <span class="o">==</span> 0:
</span></span><span class="line"><span class="cl">         Error
</span></span></code></pre></td></tr></table>
</div>
</div><p><code>4.5.1.2. Base</code></p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">   <span class="k">if</span> <span class="nv">Sign</span> <span class="o">==</span> 0:
</span></span><span class="line"><span class="cl">      <span class="nv">Base</span> <span class="o">=</span> ReqInsertCount + DeltaBase
</span></span><span class="line"><span class="cl">   <span class="k">else</span>:
</span></span><span class="line"><span class="cl">      <span class="nv">Base</span> <span class="o">=</span> ReqInsertCount - DeltaBase - <span class="m">1</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p><code>4.5.2. Indexed Field Line</code></p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">  <span class="m">0</span>   <span class="m">1</span>   <span class="m">2</span>   <span class="m">3</span>   <span class="m">4</span>   <span class="m">5</span>   <span class="m">6</span>   <span class="m">7</span>
</span></span><span class="line"><span class="cl">+---+---+---+---+---+---+---+---+
</span></span><span class="line"><span class="cl"><span class="p">|</span> <span class="m">1</span> <span class="p">|</span> T <span class="p">|</span>      Index <span class="o">(</span>6+<span class="o">)</span>       <span class="p">|</span>
</span></span><span class="line"><span class="cl">+---+---+-----------------------+
</span></span></code></pre></td></tr></table>
</div>
</div><p><code>4.5.3. Indexed Field Line with Post-Base Index</code></p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">  <span class="m">0</span>   <span class="m">1</span>   <span class="m">2</span>   <span class="m">3</span>   <span class="m">4</span>   <span class="m">5</span>   <span class="m">6</span>   <span class="m">7</span>
</span></span><span class="line"><span class="cl">+---+---+---+---+---+---+---+---+
</span></span><span class="line"><span class="cl"><span class="p">|</span> <span class="m">0</span> <span class="p">|</span> <span class="m">0</span> <span class="p">|</span> <span class="m">0</span> <span class="p">|</span> <span class="m">1</span> <span class="p">|</span>  Index <span class="o">(</span>4+<span class="o">)</span>   <span class="p">|</span>
</span></span><span class="line"><span class="cl">+---+---+---+---+---------------+
</span></span></code></pre></td></tr></table>
</div>
</div><p><code>4.5.4. Literal Field Line with Name Reference</code></p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span><span class="lnt">6
</span><span class="lnt">7
</span><span class="lnt">8
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">     <span class="m">0</span>   <span class="m">1</span>   <span class="m">2</span>   <span class="m">3</span>   <span class="m">4</span>   <span class="m">5</span>   <span class="m">6</span>   <span class="m">7</span>
</span></span><span class="line"><span class="cl">   +---+---+---+---+---+---+---+---+
</span></span><span class="line"><span class="cl">   <span class="p">|</span> <span class="m">0</span> <span class="p">|</span> <span class="m">1</span> <span class="p">|</span> N <span class="p">|</span> T <span class="p">|</span>Name Index <span class="o">(</span>4+<span class="o">)</span><span class="p">|</span>
</span></span><span class="line"><span class="cl">   +---+---+---+---+---------------+
</span></span><span class="line"><span class="cl">   <span class="p">|</span> H <span class="p">|</span>     Value Length <span class="o">(</span>7+<span class="o">)</span>     <span class="p">|</span>
</span></span><span class="line"><span class="cl">   +---+---------------------------+
</span></span><span class="line"><span class="cl">   <span class="p">|</span>  Value String <span class="o">(</span>Length bytes<span class="o">)</span>  <span class="p">|</span>
</span></span><span class="line"><span class="cl">   +-------------------------------+
</span></span></code></pre></td></tr></table>
</div>
</div><p><code>4.5.5. Literal Field Line with Post-Base Name Reference</code></p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span><span class="lnt">6
</span><span class="lnt">7
</span><span class="lnt">8
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">     <span class="m">0</span>   <span class="m">1</span>   <span class="m">2</span>   <span class="m">3</span>   <span class="m">4</span>   <span class="m">5</span>   <span class="m">6</span>   <span class="m">7</span>
</span></span><span class="line"><span class="cl">   +---+---+---+---+---+---+---+---+
</span></span><span class="line"><span class="cl">   <span class="p">|</span> <span class="m">0</span> <span class="p">|</span> <span class="m">0</span> <span class="p">|</span> <span class="m">0</span> <span class="p">|</span> <span class="m">0</span> <span class="p">|</span> N <span class="p">|</span>NameIdx<span class="o">(</span>3+<span class="o">)</span><span class="p">|</span>
</span></span><span class="line"><span class="cl">   +---+---+---+---+---+-----------+
</span></span><span class="line"><span class="cl">   <span class="p">|</span> H <span class="p">|</span>     Value Length <span class="o">(</span>7+<span class="o">)</span>     <span class="p">|</span>
</span></span><span class="line"><span class="cl">   +---+---------------------------+
</span></span><span class="line"><span class="cl">   <span class="p">|</span>  Value String <span class="o">(</span>Length bytes<span class="o">)</span>  <span class="p">|</span>
</span></span><span class="line"><span class="cl">   +-------------------------------+
</span></span></code></pre></td></tr></table>
</div>
</div><p><code>4.5.6. Literal Field Line with Literal Name</code></p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">     <span class="m">0</span>   <span class="m">1</span>   <span class="m">2</span>   <span class="m">3</span>   <span class="m">4</span>   <span class="m">5</span>   <span class="m">6</span>   <span class="m">7</span>
</span></span><span class="line"><span class="cl">   +---+---+---+---+---+---+---+---+
</span></span><span class="line"><span class="cl">   <span class="p">|</span> <span class="m">0</span> <span class="p">|</span> <span class="m">0</span> <span class="p">|</span> <span class="m">1</span> <span class="p">|</span> N <span class="p">|</span> H <span class="p">|</span>NameLen<span class="o">(</span>3+<span class="o">)</span><span class="p">|</span>
</span></span><span class="line"><span class="cl">   +---+---+---+---+---+-----------+
</span></span><span class="line"><span class="cl">   <span class="p">|</span>  Name String <span class="o">(</span>Length bytes<span class="o">)</span>   <span class="p">|</span>
</span></span><span class="line"><span class="cl">   +---+---------------------------+
</span></span><span class="line"><span class="cl">   <span class="p">|</span> H <span class="p">|</span>     Value Length <span class="o">(</span>7+<span class="o">)</span>     <span class="p">|</span>
</span></span><span class="line"><span class="cl">   +---+---------------------------+
</span></span><span class="line"><span class="cl">   <span class="p">|</span>  Value String <span class="o">(</span>Length bytes<span class="o">)</span>  <span class="p">|</span>
</span></span><span class="line"><span class="cl">   +-------------------------------+
</span></span></code></pre></td></tr></table>
</div>
</div><p>Literal Field Line with Literal Name</p>

    </article>
    
    
<script defer src="/js/clipboard.min.c168d3a04c45a631be76437054619a4a3b30107960cb9730be96012fef5762b0.js"></script>

<script defer src="/js/helper/prev.min.js"></script>

<script defer src="/js/helper/prop.min.js"></script>
<script>
  'use strict';
  document.addEventListener('DOMContentLoaded', function () {
    
    var clipInit = false;
    var preChromaElem = document.querySelectorAll('pre.chroma');
    var langCodeElem = document.querySelectorAll('.language-code');
    var dollarCodeElem = document.querySelectorAll('div.language-\\$');
    var gtCodeElem = document.querySelectorAll('div.language-\\>');

    var makeClipboard = function(elem) {
      var code = elem,
          text = elem.textContent;
        
      if (text.length > 15) {
        if (!clipInit) {
          var text, clip = new ClipboardJS('.copy-to-clipboard', {
            text: function (trigger) {
              var codeElem = prev(trigger).querySelectorAll('code');
              if (codeElem.length > 1) {
                text = prev(trigger).querySelector('code[class^="language-"]').textContent;
              } else {
                text = prev(trigger).querySelector('code').textContent;
              }

              return text.replace(/^\$\s/gm, '');
            }
          });

          var inPre;
          clip.on('success', function (e) {
            e.clearSelection();
            inPre = prop(e.trigger.parentNode, 'tagName') == 'PRE';
            e.trigger.setAttribute('aria-label', 'Copied to clipboard!');
            e.trigger.classList.add('tooltipped');
            e.trigger.classList.add('tooltipped-w');
          });

          clip.on('error', function (e) {
            inPre = prop(e.trigger.parentNode, 'tagName') == 'PRE';
            e.trigger.setAttribute('aria-label', e.action.toString());
            e.trigger.classList.add('tooltipped');
            e.trigger.classList.add('tooltipped-w');
          });

          clipInit = true;
        }

        var notAllowedClass = ['language-mermaid', 'language-viz', 'language-wave', 'language-chart', 'language-msc', 'language-flowchart'];
        var isNotAllowedIncluded = false;
        var curClassName = code.getAttribute('class');

        for (var i = 0; i < notAllowedClass.length; i++) {
          if (curClassName && curClassName.startsWith(notAllowedClass[i])) {
            isNotAllowedIncluded = true;
            break;
          }
        }

        if (!isNotAllowedIncluded) {
          if (curClassName) {
            var newClipboardElem = document.createElement('span');
            newClipboardElem.setAttribute('class', 'copy-to-clipboard');
            newClipboardElem.setAttribute('title', 'Copy to clipboard');
            elem.parentNode.parentNode.insertBefore(newClipboardElem, elem.parentNode.nextElementSibling);
          }
        }
      }
    }

    var makeSymbolClipboard = function(elem) {
      var clipboardSpan = document.createElement('span');
      clipboardSpan.setAttribute('class', 'copy-to-clipboard');
      clipboardSpan.setAttribute('title', 'Copy to clipboard');
      elem.parentNode.parentNode.insertBefore(clipboardSpan, elem.parentNode.nextElementSibling);
    }

    preChromaElem ? 
    preChromaElem.forEach(function(elem) {
      elem.querySelectorAll('code').forEach(function(codeElem) {
        makeClipboard(codeElem);
      });
    }) : null;
    
    langCodeElem ? 
    langCodeElem.forEach(function(elem) {
      elem.querySelectorAll('code').forEach(function (codeElem) {
        makeClipboard(codeElem);
      });
    }) : null;

    dollarCodeElem ? 
    dollarCodeElem.forEach(function(elem) {
      elem.querySelectorAll('code').forEach(function (codeElem) {
        makeSymbolClipboard(codeElem);
      });
    }) : null;

    gtCodeElem ?
    gtCodeElem.forEach(function(elem) {
      elem.querySelectorAll('code').forEach(function (codeElem) {
        makeSymbolClipboard(codeElem);
      });
    }) : null;
    
  });
</script>
    <script>
  'use strict';
  
  function wrap(el, wrapper) {
    el.parentNode.insertBefore(wrapper, el);
    wrapper.appendChild(el);
  }

  (function () {
    var singleContentsElem = document.querySelector('.single__contents');
    singleContentsElem ? 
    singleContentsElem.querySelectorAll('pre > code').forEach(function(elem) {
      var dataLang = elem.getAttribute('data-lang');
      var dataLangWrapper = document.createElement('div');
      var code = null;
      var codeTitle = null;

      if (dataLang && dataLang.includes(':')) {
        code = dataLang.split(':')[0];
        codeTitle = dataLang.split(':')[1];

        dataLangWrapper.className = 'language-' + code;
        dataLangWrapper.setAttribute('data-lang', codeTitle);

        elem.className = 'language-' + code;
        elem.setAttribute('data-lang', codeTitle);
        elem.setAttribute('id', codeTitle);
      } else if (!dataLang) {
        dataLangWrapper.setAttribute('data-lang', 'Code');
        dataLangWrapper.className = 'language-code';
      }

      if (!dataLang || codeTitle) {
        wrap(elem.parentNode, dataLangWrapper);
      }

    }) : null;
  })();

  var langCodeElem = document.querySelectorAll('.language-code');
  langCodeElem ? langCodeElem.forEach(function (elem) {
    var newElem = document.createElement('span');
    newElem.className = 'copy-to-clipboard';
    newElem.setAttribute('title', 'Copy to clipboard');
    elem.append(newElem);
  }) : null;
  

  

  
  var dollarCodeElem = document.querySelectorAll('div.language-\\$');
  var gtCodeElem = document.querySelectorAll('div.language-\\>');

  dollarCodeElem ?
  dollarCodeElem.forEach(function(elem) {
    var lnts = elem.parentNode.parentNode ? elem.parentNode.parentNode.querySelectorAll('.lnt') : null;
    lnts ? 
    lnts.forEach(function(lnt) {
      lnt.innerHTML = '$<br/>';
    }) : null;
  }) : null;

  gtCodeElem ?
  gtCodeElem.forEach(function(elem) {
    var lnts = elem.parentNode.parentNode ? elem.parentNode.parentNode.querySelectorAll('.lnt') : null;
    lnts ? 
    lnts.forEach(function(lnt) {
      lnt.innerHTML = '><br/>';
    }) : null;
  }) : null;
  
</script>
    
<div class="donation">
  <div class="donation__message">
    Share on
  </div>
  <div class="donation__icons">
    
    
    
      
    
      
    
  </div>
</div>


    
    
<div class="whoami__gutter"></div>
<hr class="hr-slash whoami-hr"/>
<section class="whoami">
  <div class="whoami__image-wrapper">
    
    
      
        <img data-src="/images/whoami/avatar.jpg" src="data:image/svg+xml,%0A%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24'%3E%3Cpath fill='none' d='M0 0h24v24H0V0z'/%3E%3Cpath fill='%23aaa' d='M19 3H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zm-1 16H6c-.55 0-1-.45-1-1V6c0-.55.45-1 1-1h12c.55 0 1 .45 1 1v12c0 .55-.45 1-1 1zm-4.44-6.19l-2.35 3.02-1.56-1.88c-.2-.25-.58-.24-.78.01l-1.74 2.23c-.26.33-.02.81.39.81h8.98c.41 0 .65-.47.4-.8l-2.55-3.39c-.19-.26-.59-.26-.79 0z'/%3E%3C/svg%3E" alt="ruokeqx" class="lazyload whoami__image"/>
      
    
  </div>
  <div class="whoami__contents">
    <div class="whoami__written-by">
      WRITTEN BY
    </div>
    <div class="whoami__title">
      
        ruokeqx
      
    </div>
    <div class="whoami__desc">
      
        
      
    </div>
    <div class="whoami__social">
      
      
      
      
      
      
      
      
      <a href="ruokeqx@163.com" title="email" aria-label="email">
        <svg xmlns="http://www.w3.org/2000/svg" width="25" height="25" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path fill="currentColor" d="M20 4H4c-1.1 0-1.99.9-1.99 2L2 18c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V6c0-1.1-.9-2-2-2zm-.4 4.25l-7.07 4.42c-.32.2-.74.2-1.06 0L4.4 8.25c-.25-.16-.4-.43-.4-.72 0-.67.73-1.07 1.3-.72L12 11l6.7-4.19c.57-.35 1.3.05 1.3.72 0 .29-.15.56-.4.72z"/></svg>
      </a>
      
      
      
      
      
      
      
      <a href="https://github.com/ruokeqx" title="github" aria-label="github">
        <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="25" height="25" viewBox="0 0 24 24" version="1.1">
<g id="surface3680">
<path fill="currentColor" d="M 10.898438 2.101562 C 6.300781 2.601562 2.601562 6.300781 2.101562 10.800781 C 1.601562 15.5 4.300781 19.699219 8.398438 21.300781 C 8.699219 21.398438 9 21.199219 9 20.800781 L 9 19.199219 C 9 19.199219 8.601562 19.300781 8.101562 19.300781 C 6.699219 19.300781 6.101562 18.101562 6 17.398438 C 5.898438 17 5.699219 16.699219 5.398438 16.398438 C 5.101562 16.300781 5 16.300781 5 16.199219 C 5 16 5.300781 16 5.398438 16 C 6 16 6.5 16.699219 6.699219 17 C 7.199219 17.800781 7.800781 18 8.101562 18 C 8.5 18 8.800781 17.898438 9 17.800781 C 9.101562 17.101562 9.398438 16.398438 10 16 C 7.699219 15.5 6 14.199219 6 12 C 6 10.898438 6.5 9.800781 7.199219 9 C 7.101562 8.800781 7 8.300781 7 7.601562 C 7 7.199219 7 6.601562 7.300781 6 C 7.300781 6 8.699219 6 10.101562 7.300781 C 10.601562 7.101562 11.300781 7 12 7 C 12.699219 7 13.398438 7.101562 14 7.300781 C 15.300781 6 16.800781 6 16.800781 6 C 17 6.601562 17 7.199219 17 7.601562 C 17 8.398438 16.898438 8.800781 16.800781 9 C 17.5 9.800781 18 10.800781 18 12 C 18 14.199219 16.300781 15.5 14 16 C 14.601562 16.5 15 17.398438 15 18.300781 L 15 20.898438 C 15 21.199219 15.300781 21.5 15.699219 21.398438 C 19.398438 19.898438 22 16.300781 22 12.101562 C 22 6.101562 16.898438 1.398438 10.898438 2.101562 Z M 10.898438 2.101562 "/>
</g>
</svg>

      </a>
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
    </div>
  </div>
</section>
<hr class="hr-slash whoami-hr" />


    <section class="related">
    
    
    <h1 class="related__title">
      <hr class="hr-dots"/>
      <div>
        See Also
      </div>
      <hr class="hr-dots"/>
    </h1>
    <ul class="related-ul">
        
        <li>
          <a href="/posts/quichttp3_demo/" class="related__link">浅尝QUIC和HTTP3</a>
        </li>
        
        <li>
          <a href="/posts/ebpf_bypass_iptables/" class="related__link">eBPF bypass iptables</a>
        </li>
        
        <li>
          <a href="/posts/bpf_uprobe_bypass_go_tls/" class="related__link">eBPF Uprobe bypass Go tls——抓取https明文流量</a>
        </li>
        
        <li>
          <a href="/posts/cap%E6%A0%BC%E5%BC%8F/" class="related__link">pcap和pcapng格式的一点研究</a>
        </li>
        
    </ul>
    
  </section>
    <div class="grow"></div>
<nav class="pagination-single">
  
    
      <a href="https://ruokeqx.gitee.io/posts/quichttp3_demo/" class="pagination-single__left">
        <div class="pagination-single__icon">
          <svg xmlns="http://www.w3.org/2000/svg" width="25" height="25" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path fill="currentColor" d="M19 11H7.83l4.88-4.88c.39-.39.39-1.03 0-1.42-.39-.39-1.02-.39-1.41 0l-6.59 6.59c-.39.39-.39 1.02 0 1.41l6.59 6.59c.39.39 1.02.39 1.41 0 .39-.39.39-1.02 0-1.41L7.83 13H19c.55 0 1-.45 1-1s-.45-1-1-1z"/></svg>
        </div>
        <div class="pagination-single__left-title">浅尝QUIC和HTTP3</div>      
      </a>
    
    <div class="grow"></div>
    
      <a href="https://ruokeqx.gitee.io/posts/quic-go_source/" class="pagination-single__right">      
        <div class="pagination-single__right-title">quic-go库源码阅读</div>
        <div class="pagination-single__icon">
          <svg xmlns="http://www.w3.org/2000/svg" width="25" height="25" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path fill="currentColor" d="M5 13h11.17l-4.88 4.88c-.39.39-.39 1.03 0 1.42.39.39 1.02.39 1.41 0l6.59-6.59c.39-.39.39-1.02 0-1.41l-6.58-6.6c-.39-.39-1.02-.39-1.41 0-.39.39-.39 1.02 0 1.41L16.17 11H5c-.55 0-1 .45-1 1s.45 1 1 1z"/></svg>
        </div>
      </a>
    
  
</nav>
    
    <div class="modal micromodal-slide" id="modal" aria-hidden="true">
  <div class="modal__overlay" tabindex="-1" data-micromodal-close>
    <div class="modal__container" role="dialog" aria-modal="true" aria-labelledby="modal-title">
      
      <div class="modal__content" id="modal-content">
        <div id="mySwipe" class="swipe">
          <div class="swipe-wrap">
          </div>
        </div>
      </div>

      <span class="modal__items">
        
        <span class="modal__header">
          <div class="modal__paging" title="Page Info" aria-label="Current Page">
          </div>
          <div class="modal__icon modal__toolbar modal__toolbar--close" title="Close" aria-label="Close Button" data-micromodal-close>
            <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 26 26" width="25" height="25"><path fill="currentColor" d="M 21.734375 19.640625 L 19.636719 21.734375 C 19.253906 22.121094 18.628906 22.121094 18.242188 21.734375 L 13 16.496094 L 7.761719 21.734375 C 7.375 22.121094 6.746094 22.121094 6.363281 21.734375 L 4.265625 19.640625 C 3.878906 19.253906 3.878906 18.628906 4.265625 18.242188 L 9.503906 13 L 4.265625 7.761719 C 3.882813 7.371094 3.882813 6.742188 4.265625 6.363281 L 6.363281 4.265625 C 6.746094 3.878906 7.375 3.878906 7.761719 4.265625 L 13 9.507813 L 18.242188 4.265625 C 18.628906 3.878906 19.257813 3.878906 19.636719 4.265625 L 21.734375 6.359375 C 22.121094 6.746094 22.121094 7.375 21.738281 7.761719 L 16.496094 13 L 21.734375 18.242188 C 22.121094 18.628906 22.121094 19.253906 21.734375 19.640625 Z"/></svg>
          </div>
          <div class="modal__icon modal__toolbar modal__toolbar--full" title="Full Screen" aria-label="Full Screen Button">
            <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="25" height="25"><path fill="currentColor" d="M 5 3 C 3.9069372 3 3 3.9069372 3 5 L 3 8 A 1.0001 1.0001 0 1 0 5 8 L 5 5 L 8 5 A 1.0001 1.0001 0 1 0 8 3 L 5 3 z M 16 3 A 1.0001 1.0001 0 1 0 16 5 L 19 5 L 19 8 A 1.0001 1.0001 0 1 0 21 8 L 21 5 C 21 3.9069372 20.093063 3 19 3 L 16 3 z M 3.984375 14.986328 A 1.0001 1.0001 0 0 0 3 16 L 3 19 C 3 20.093063 3.9069372 21 5 21 L 8 21 A 1.0001 1.0001 0 1 0 8 19 L 5 19 L 5 16 A 1.0001 1.0001 0 0 0 3.984375 14.986328 z M 19.984375 14.986328 A 1.0001 1.0001 0 0 0 19 16 L 19 19 L 16 19 A 1.0001 1.0001 0 1 0 16 21 L 19 21 C 20.093063 21 21 20.093063 21 19 L 21 16 A 1.0001 1.0001 0 0 0 19.984375 14.986328 z"/></svg>
          </div>
          <div class="modal__icon modal__toolbar modal__toolbar--normal" title="Normal Screen" aria-label="Normal Screen Button">
            <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 50 50" width="25" height="25"><path fill="currentColor" d="M 16.96875 4.972656 C 15.867188 4.988281 14.984375 5.894531 15 7 L 15 15 L 7 15 C 6.277344 14.988281 5.609375 15.367188 5.246094 15.992188 C 4.878906 16.613281 4.878906 17.386719 5.246094 18.007813 C 5.609375 18.632813 6.277344 19.011719 7 19 L 19 19 L 19 7 C 19.007813 6.460938 18.796875 5.941406 18.414063 5.558594 C 18.03125 5.175781 17.511719 4.964844 16.96875 4.972656 Z M 32.96875 4.972656 C 31.921875 4.988281 31.0625 5.8125 31.003906 6.859375 C 31 6.90625 31 6.953125 31 7 L 31 19 L 43 19 C 43.066406 19 43.132813 19 43.199219 18.992188 C 44.269531 18.894531 45.070313 17.972656 45.015625 16.902344 C 44.964844 15.828125 44.074219 14.988281 43 15 L 35 15 L 35 7 C 35.007813 6.460938 34.796875 5.941406 34.414063 5.558594 C 34.03125 5.175781 33.511719 4.964844 32.96875 4.972656 Z M 7 31 C 6.277344 30.988281 5.609375 31.367188 5.246094 31.992188 C 4.878906 32.613281 4.878906 33.386719 5.246094 34.007813 C 5.609375 34.632813 6.277344 35.011719 7 35 L 15 35 L 15 43 C 14.988281 43.722656 15.367188 44.390625 15.992188 44.753906 C 16.613281 45.121094 17.386719 45.121094 18.007813 44.753906 C 18.632813 44.390625 19.011719 43.722656 19 43 L 19 31 Z M 31 31 L 31 43 C 30.988281 43.722656 31.367188 44.390625 31.992188 44.753906 C 32.613281 45.121094 33.386719 45.121094 34.007813 44.753906 C 34.632813 44.390625 35.011719 43.722656 35 43 L 35 35 L 43 35 C 43.722656 35.011719 44.390625 34.632813 44.753906 34.007813 C 45.121094 33.386719 45.121094 32.613281 44.753906 31.992188 C 44.390625 31.367188 43.722656 30.988281 43 31 Z"/></svg>
          </div>
        </span>
        
        <div class="modal__icon modal__arrow modal__arrow--left" title="Arrow Left" aria-label="Arrow Left Button">
          <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 26 26" width="28" height="28"><path fill="currentColor" d="M 23.28125 11 L 10 10 L 10 6.851563 C 10 6.523438 9.839844 6.277344 9.519531 6.03125 C 9.199219 5.949219 8.878906 5.949219 8.640625 6.113281 C 5.359375 8.410156 2.238281 12.257813 2.160156 12.421875 C 2.082031 12.578125 2.007813 12.8125 2.003906 12.976563 C 2.003906 12.980469 2 12.988281 2 12.992188 C 2 13.15625 2.078125 13.402344 2.160156 13.484375 C 2.238281 13.648438 5.28125 17.507813 8.640625 19.804688 C 8.960938 19.96875 9.28125 20.050781 9.519531 19.886719 C 9.839844 19.722656 10 19.476563 10 19.148438 L 10 16 L 23.28125 15 C 23.679688 14.679688 24 13.875 24 12.992188 C 24 12.195313 23.761719 11.320313 23.28125 11 Z"/></svg>
        </div>
        
        <div class="modal__icon modal__arrow modal__arrow--right" title="Arrow Right" aria-label="Arrow Right Button">

          <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 26 26" width="28" height="28"><path fill="currentColor" d="M 2.71875 11.023438 L 16 10.023438 L 16 6.875 C 16 6.546875 16.160156 6.300781 16.480469 6.054688 C 16.800781 5.972656 17.121094 5.972656 17.359375 6.136719 C 20.640625 8.433594 23.761719 12.28125 23.839844 12.445313 C 23.917969 12.601563 23.992188 12.835938 23.996094 13 C 23.996094 13.003906 24 13.011719 24 13.015625 C 24 13.179688 23.921875 13.425781 23.839844 13.507813 C 23.761719 13.671875 20.71875 17.53125 17.359375 19.828125 C 17.039063 19.992188 16.71875 20.074219 16.480469 19.910156 C 16.160156 19.746094 16 19.5 16 19.171875 L 16 16.023438 L 2.71875 15.023438 C 2.320313 14.703125 2 13.898438 2 13.015625 C 2 12.21875 2.238281 11.34375 2.71875 11.023438 Z"/></svg>
        </div>

        <div class="modal__caption">
          <div class="modal__caption--text">
          </div>
        </div>

      </span>
    </div>
  </div>
</div>


<script defer src="/js/swipe.min.b5af2be70ffc9ba2e83412609aa18b5b025c69399f9e1dce09d444a636a38cd0.js"></script>

<script defer src="/js/micromodal.min.de01b44b2f383056bbcaf6ee921fd385d79108ec1129afd0eb2f3f5a07e11f45.js"></script>

<script defer src="/js/helper/fadeinout.min.js"></script>

<script>
document.addEventListener('DOMContentLoaded', function () {
  
   
  var docElem = document.documentElement;

   
  function openFullscreen() {
    if (docElem.requestFullscreen) {
      docElem.requestFullscreen();
    } else if (docElem.mozRequestFullScreen) {  
      docElem.mozRequestFullScreen();
    } else if (docElem.webkitRequestFullscreen) {  
      docElem.webkitRequestFullscreen();
    } else if (docElem.msRequestFullscreen) {  
      docElem.msRequestFullscreen();
    }
  }

   
  function closeFullscreen() {
    if (document.fullscreenElement ||
      document.webkitFullscreenElement ||
      document.mozFullScreenElement) {
      if (document.exitFullscreen) {
        document.exitFullscreen();
      } else if (document.mozCancelFullScreen) {  
        document.mozCancelFullScreen();
      } else if (document.webkitExitFullscreen) {  
        document.webkitExitFullscreen();
      } else if (document.msExitFullscreen) {  
        document.msExitFullscreen();
      }
    }
  }

  var modal = document.getElementById('modal');
  var galleryContainerElem = document.querySelector('.gallery__container');
  var swipeWrapElem = document.querySelector('.swipe-wrap');
  var mySwipeElem = document.getElementById('mySwipe');
  var arrowLeftElem = document.querySelector('.modal__arrow--left');
  var arrowRightElem = document.querySelector('.modal__arrow--right');
  var closeElem = document.querySelector('.modal__toolbar--close');
  var fullElem = document.querySelector('.modal__toolbar--full');
  var normalElem = document.querySelector('.modal__toolbar--normal');
  var captionElem = document.querySelector('.modal__caption');
  var pagingElem = document.querySelector('.modal__paging');
  var itemsElem = document.querySelector('.modal__items');
  var imgTotalNum = null;
  var myFadeTimeout = null;
  var mySwipe = null;
  var keydownFunction = function (e) {
    if (e.key === 'ArrowRight') {
      if (modal && modal.classList.contains('is-open')) {
        mySwipe.next();
      }
    } else if (e.key === 'ArrowLeft') {
      if (modal && modal.classList.contains('is-open')) {
        mySwipe.prev();
      }
    }
  }

  if (galleryContainerElem) {
    imgTotalNum = galleryContainerElem.querySelectorAll('img').length;
  } else {
    galleryContainerElem = document.querySelector('.single__contents');
    imgTotalNum = galleryContainerElem.querySelectorAll('img').length;
  }

  MicroModal.init({
    onClose: function () {
      if (mySwipe) {
        mySwipe.kill();
        mySwipe = null;
        closeFullscreen();
      }
      window.removeEventListener('keydown', keydownFunction);
    },
    disableScroll: true,
    disableFocus: true,
    awaitOpenAnimation: false,
    awaitCloseAnimation: false,
    debugMode: false,
  });

  var imageLoad = function(src) {
    return new Promise(function(resolve, reject) {
      var newImg = new Image;
      newImg.onload = function() {
        resolve(newImg);
      }
      newImg.onerror = reject;
      newImg.src = src;
    });
  }

  galleryContainerElem.querySelectorAll('img').forEach(function (elem, idx) {
    elem.style.cursor = 'pointer';

    var clonedElem = elem.cloneNode(true);
    clonedElem.style.maxHeight = '100%';
    clonedElem.style.maxWidth = '100%';
    clonedElem.onclick = function (e) {
      e.stopPropagation();
    }

    var wrapper = document.createElement('div');
    wrapper.style.width = '100%';
    wrapper.style.height = '100vh';
    wrapper.setAttribute('data-micromodal-close', '');
    wrapper.onclick = function () {
      if (mySwipe) {
        mySwipe.kill();
        mySwipe = null;
      }
    }
    wrapper.onmouseenter = function () {
      clearTimeout(myFadeTimeout);
      fadeIn(itemsElem, 200);
    };
    wrapper.onmouseleave = function () {
      myFadeTimeout = setTimeout(function () {
        fadeOut(itemsElem, 200);
      }, 2500);
    }
    wrapper.ontouchstart = function() {
      fadeIn(itemsElem, 200);
    }
    wrapper.append(clonedElem);
    swipeWrapElem.append(wrapper);

    elem.addEventListener('click', async function (e) {
      MicroModal.show('modal');
      if (mySwipe) {
        mySwipe.kill();
        mySwipe = null;
      }

      var imgSrc = e.target.getAttribute('data-src') || e.target.getAttribute('src');
      var img = await imageLoad(imgSrc);
      clonedElem.style.width = img.width + 'px';
      clonedElem.style.height = img.height + 'px';
      
      
      mySwipe = new Swipe(mySwipeElem, {
        startSlide: idx,
        draggable: true,
        autoRestart: false,
        continuous: false,
        disableScroll: true,
        stopPropagation: true,
        callback: async function (index, element) {
          
          var imgElem = element.querySelector('img');
          var imgSrc = imgElem.getAttribute('data-src') || imgElem.getAttribute('src');
          var img = await imageLoad(imgSrc);
          imgElem.style.width = img.width + 'px';
          imgElem.style.height = img.height + 'px';

          
          if (captionElem && imgElem) {
            var caption = null;
            if (imgElem.getAttribute('data-caption')) {
              caption = imgElem.getAttribute('data-caption');
            } else if (imgElem.getAttribute('title')) {
              caption = imgElem.getAttribute('title');
            } else if (imgElem.getAttribute('alt')) {
              caption = imgElem.getAttribute('alt');
            } else {
              caption = imgElem.getAttribute('src');
            }

            captionElem.querySelector('.modal__caption--text').innerText = caption;
            pagingElem.innerText = (index + 1) + ' / ' + imgTotalNum;

            clearTimeout(myFadeTimeout);
            fadeIn(itemsElem, 200);
          }
        },
      });

      fadeIn(itemsElem);

      
      if (captionElem) {
        var caption = null;
        if (e.target.getAttribute('data-caption')) {
          caption = e.target.getAttribute('data-caption');
        } else if (e.target.getAttribute('title')) {
          caption = e.target.getAttribute('title');
        } else if (e.target.getAttribute('alt')) {
          caption = e.target.getAttribute('alt');
        } else {
          caption = e.target.getAttribute('src');
        }

        captionElem.querySelector('.modal__caption--text').innerText = caption;
        pagingElem.innerText = (idx + 1) + ' / ' + imgTotalNum;
      }

      if (normalElem && fullElem) {
        normalElem.style.zIndex = -1;
        normalElem.style.opacity = 0;
        fullElem.style.zIndex = 25;
        fullElem.style.opacity = 1;
      }
    });

    window.addEventListener('keydown', keydownFunction);
  });

  arrowLeftElem ?
    arrowLeftElem.addEventListener('click', function (e) {
      if (mySwipe) {
        mySwipe.prev();
      }
    }) : null;
  arrowRightElem ?
    arrowRightElem.addEventListener('click', function (e) {
      if (mySwipe) {
        mySwipe.next();
      }
    }) : null;

  closeElem ?
    closeElem.addEventListener('click', function () {
      if (mySwipe) {
        mySwipe.kill();
        mySwipe = null;
      }
      closeFullscreen();
      MicroModal.close('modal');
    }) : null;

  fullElem ?
    fullElem.addEventListener('click', function (e) {
      openFullscreen();
      if (normalElem) {
        normalElem.style.zIndex = 25;
        normalElem.style.opacity = 1;
        fullElem.style.zIndex = -1;
        fullElem.style.opacity = 0;
      }
    }) : null;

  normalElem ?
    normalElem.addEventListener('click', function (e) {
      closeFullscreen();
      if (fullElem) {
        fullElem.style.zIndex = 25;
        fullElem.style.opacity = 1;
        normalElem.style.zIndex = -1;
        normalElem.style.opacity = 0;
      }
    }) : null;
  
});
</script>

    <div class="hide">
      

<div class="search">
  <span class="icon">
    <svg xmlns="http://www.w3.org/2000/svg" width="22" height="22" fill="currentColor" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M15.5 14h-.79l-.28-.27c1.2-1.4 1.82-3.31 1.48-5.34-.47-2.78-2.79-5-5.59-5.34-4.23-.52-7.79 3.04-7.27 7.27.34 2.8 2.56 5.12 5.34 5.59 2.03.34 3.94-.28 5.34-1.48l.27.28v.79l4.25 4.25c.41.41 1.08.41 1.49 0 .41-.41.41-1.08 0-1.49L15.5 14zm-6 0C7.01 14 5 11.99 5 9.5S7.01 5 9.5 5 14 7.01 14 9.5 11.99 14 9.5 14z"/></svg>
  </span>
  <input id="search" aria-label="Site Search" class="input" type="text" placeholder="Search" autocomplete="off">
  <div id="search-results" class="dropdown">
    <div id="search-menu" class="dropdown-menu" role="menu">
    </div>
  </div>
</div>


    </div>
  </div>
</main>


<aside class="single__side main-side">
  


<section class="sidebar hide">
  <script>document.querySelector('.sidebar').classList.remove('hide')</script>
  <div class="toc__flexbox" data-position="absolute">
    <h6 class="toc__title" data-ani="true">What&#39;s on this Page</h6>
    
      <label class="switch" data-ani="true">
        <input id="toggle-toc" aria-label="Toggle TOC" type="checkbox" >
        <span class="slider round"></span>
      </label>
    
  </div>
  <div class="toc hide" data-dir="ltr" data-folding="true" data-ani="true">
    <nav id="TableOfContents">
  <ul>
    <li><a href="#rfc8999">RFC8999</a>
      <ul>
        <li><a href="#1-quic的一个高度抽象的描述">1. QUIC的一个高度抽象的描述</a></li>
        <li><a href="#2-所有quic版本固定的属性">2. 所有QUIC版本固定的属性</a></li>
        <li><a href="#3-规约及定义">3. 规约及定义</a></li>
        <li><a href="#4-标准规范">4. 标准规范</a></li>
        <li><a href="#5-quic-packets">5. QUIC Packets</a>
          <ul>
            <li><a href="#51-长header">5.1 长Header</a></li>
            <li><a href="#52-短header">5.2 短Header</a></li>
            <li><a href="#53-连接id">5.3 连接ID</a></li>
            <li><a href="#54-版本">5.4 版本</a></li>
          </ul>
        </li>
        <li><a href="#6-版本协商">6. 版本协商</a></li>
        <li><a href="#7-安全及隐私考量">7. 安全及隐私考量</a>
          <ul>
            <li><a href="#附录a不正确的猜想">附录A：不正确的猜想</a></li>
          </ul>
        </li>
      </ul>
    </li>
    <li><a href="#rfc9000">RFC9000</a>
      <ul>
        <li><a href="#0x2流">0x2、流</a>
          <ul>
            <li><a href="#0x24流操作">0x24、流操作</a></li>
          </ul>
        </li>
        <li><a href="#0x3流状态">0x3、流状态</a>
          <ul>
            <li><a href="#0x31发送流状态">0x31、发送流状态</a></li>
            <li><a href="#0x32接收流状态">0x32、接收流状态</a></li>
            <li><a href="#0x33permitted-frame-types">0x33、Permitted Frame Types</a></li>
            <li><a href="#0x34双向流状态">0x34、双向流状态</a></li>
            <li><a href="#0x35请求状态转换">0x35、请求状态转换</a></li>
          </ul>
        </li>
        <li><a href="#0x4流量控制">0x4、流量控制</a>
          <ul>
            <li><a href="#0x41数据流量控制">0x41、数据流量控制</a></li>
            <li><a href="#0x43流量控制性能">0x43、流量控制性能</a></li>
            <li><a href="#0x45流最终数据量">0x45、流最终数据量</a></li>
            <li><a href="#0x46并发控制">0x46、并发控制</a></li>
          </ul>
        </li>
        <li><a href="#0x5-连接">0x5 连接</a>
          <ul>
            <li><a href="#0x53-连接操作">0x53 连接操作</a></li>
          </ul>
        </li>
        <li><a href="#0x7-加密与传输握手">0x7 加密与传输握手</a></li>
        <li><a href="#0x12-packets-and-frames">0x12 Packets and Frames</a>
          <ul>
            <li><a href="#0x124-frames-and-frame-types">0x124 Frames and Frame Types</a></li>
          </ul>
        </li>
        <li><a href="#0x16-可变长整型">0x16 可变长整型</a></li>
        <li><a href="#0x17-packet-formats">0x17 Packet Formats</a></li>
        <li><a href="#0x18-传输参数编码">0x18 传输参数编码</a></li>
        <li><a href="#0x19-帧类型和格式">0x19 帧类型和格式</a></li>
      </ul>
    </li>
    <li><a href="#rfc9114">RFC9114</a>
      <ul>
        <li><a href="#第三章连接设置和管理">第三章、连接设置和管理</a></li>
        <li><a href="#第四章在http3中表达http语义">第四章、在HTTP3中表达HTTP语义</a></li>
        <li><a href="#第六章stream-mapping-and-usage">第六章、Stream Mapping and Usage</a>
          <ul>
            <li><a href="#双向流">双向流</a></li>
            <li><a href="#单向流">单向流</a></li>
          </ul>
        </li>
        <li><a href="#第七章http-framing-layer">第七章、HTTP Framing Layer</a>
          <ul>
            <li><a href="#frame-layout">Frame Layout</a></li>
            <li><a href="#frame-definitions">Frame Definitions</a></li>
          </ul>
        </li>
      </ul>
    </li>
    <li><a href="#rfc9204">RFC9204</a>
      <ul>
        <li><a href="#abstract">Abstract</a></li>
        <li><a href="#2压缩过程概述">2、压缩过程概述</a>
          <ul>
            <li><a href="#21encoder">2.1、Encoder</a></li>
            <li><a href="#22decoder">2.2、Decoder</a></li>
          </ul>
        </li>
        <li><a href="#3reference-tables">3、Reference Tables</a>
          <ul>
            <li><a href="#31static-table">3.1、Static Table</a></li>
            <li><a href="#32dynamic-table">3.2、Dynamic Table</a></li>
          </ul>
        </li>
        <li><a href="#4wire-format">4、Wire Format</a>
          <ul>
            <li><a href="#42-encoder-and-decoder-streams">4.2. Encoder and Decoder Streams</a></li>
            <li><a href="#43-encoder-指令">4.3. Encoder 指令</a></li>
            <li><a href="#44-decoder-指令">4.4. Decoder 指令</a></li>
            <li><a href="#45--field-line-representations">4.5.  Field Line Representations</a></li>
          </ul>
        </li>
      </ul>
    </li>
  </ul>
</nav>
  </div>
</section>



</aside>

<script>
  
  
  

  var enableToc = JSON.parse("true");
  var toc = JSON.parse("null");
  var tocPosition = JSON.parse("\"inner\"");
  
  var singleMainElem = document.querySelector('.single__main');
  var singleSideElem = document.querySelector('.single__side');

  enquire.register("screen and (max-width: 769px)", {
    match: function () {
      if ((enableToc || toc) && tocPosition !== "outer") {
        if (singleMainElem && singleSideElem) {
          singleMainElem.classList.remove('main-main');
          singleMainElem.classList.add('main');
          singleSideElem.classList.remove('main-side');
          singleSideElem.classList.add('hide');
        }
      } else if (tocPosition === "outer") {
        if (singleMainElem && !singleMainElem.classList.contains('main-main')) {
          singleMainElem.classList.remove('main-main');
          singleMainElem.classList.add('main');
        }
        if (singleSideElem && !singleSideElem.classList.contains('hide')) {
          singleSideElem.classList.add('hide');
        }
      }
    },
    unmatch: function () {
      if ((enableToc || toc) && tocPosition !== "outer") {
        singleMainElem.classList.remove('main');
        singleMainElem.classList.add('main-main');
        singleSideElem.classList.remove('hide');
        singleSideElem.classList.add('main-side');
      } else if (tocPosition === "outer") {
        if (singleMainElem && !singleMainElem.classList.contains('main-main')) {
          singleMainElem.classList.remove('main-main');
          singleMainElem.classList.add('main');
        }
        if (singleSideElem && !singleSideElem.classList.contains('hide')) {
          singleSideElem.classList.add('hide');
        }
      }

      var navCollapseBtn = document.querySelector('.navbar__burger');
      var navCollapse = document.getElementsByClassName('navbarm__collapse')[0];
      if (navCollapse) {
        navCollapse.setAttribute('data-open', false);
        navCollapse.style.maxHeight = 0;
        navCollapseBtn.classList.remove('is-active');
      }
      document.getElementsByClassName('navbar__menu')[0].classList.remove('is-active');
      document.getElementsByClassName('mobile-search')[0].classList.add('hide');
    },
    setup: function () { },
    deferSetup: true,
    destroy: function () { },
  });
</script>





<script defer src="/js/helper/getParents.min.js"></script>

<script defer src="/js/helper/closest.min.js"></script>

<script defer src="/js/helper/prev.min.js"></script>

<script defer src="/js/helper/prop.min.js"></script>

<script defer src="/js/helper/fadeinout.min.js"></script>

<script defer src="/js/helper/throttle.min.js"></script>






































  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/katex@0.11.1/dist/katex.min.css" integrity="sha256-V8SV2MO1FUb63Bwht5Wx9x6PVHNa02gv8BgH/uH3ung=" crossorigin="anonymous">
  <script defer src="https://cdn.jsdelivr.net/npm/katex@0.11.1/dist/katex.min.js" integrity="sha256-F/Xda58SPdcUCr&#43;xhSGz9MA2zQBPb0ASEYKohl8UCHc=" crossorigin="anonymous"></script>
  <script defer src="https://cdn.jsdelivr.net/npm/katex@0.11.1/dist/contrib/auto-render.min.js" integrity="sha256-90d2pnfw0r4K8CZAWPko4rpFXQsZvJhTBGYNkipDprI=" crossorigin="anonymous"></script>














<script>
  'use strict';

  window.onload = function() {
    var navbar = document.querySelector('.navbar');
    var singleContentsElem = document.querySelector('.single__contents');

    
    
    
    var enableBusuanzi = JSON.parse("true");
    var busuanziPagePV = JSON.parse("true");
    
    if (enableBusuanzi && busuanziPagePV) {
      var pagePvElem = document.querySelector('#busuanzi_value_page_pv');
      pagePvElem.textContent = pagePvElem.textContent.replace(/(\d)(?=(\d\d\d)+(?!\d))/g, "$1,");
    }    
    



    
    
    
    
    
    
    var enableToc = JSON.parse("true");
    var toc = JSON.parse("null");
    var hideToc = JSON.parse("true");
    var tocFlexbox = document.querySelector('.toc__flexbox');
    var tocFlexboxOuter = document.querySelector('.toc__flexbox--outer');
    var tocFolding = JSON.parse("true");
    
    if ((enableToc || toc) && document.querySelector('.toc')) {
      var tableOfContentsElem = document.querySelector('.toc').querySelector('#TableOfContents');

      tableOfContentsElem.onmouseenter = function() {
        if (navbar.classList.contains('scrolling')) {
          navbar.classList.remove('scrolling');
        }
      }

      tableOfContentsElem.onmouseleave = function() {
        if (!navbar.classList.contains('scrolling')) {
          navbar.classList.add('scrolling');
        }
      }

      if (false === tocFolding) {

      } else {
        tableOfContentsElem.querySelectorAll('ul') ?
          tableOfContentsElem.querySelectorAll('ul').forEach(function (rootUl) {
            rootUl.querySelectorAll('li').forEach(function (liElem) {
              liElem.querySelectorAll('ul').forEach(function (ulElem) {
                ulElem.style.display = 'none';
              });
            });
          }) : null;
      }

      if (tableOfContentsElem) {
        if (tableOfContentsElem.querySelectorAll('a').length > 0) {
          tableOfContentsElem.querySelectorAll('a').forEach(function (elem) {
            elem.addEventListener('click', function () {
              var id = elem.getAttribute('id');

              if (!navbar.classList.contains('scrolling')) {
                navbar.classList.remove('navbar--show');
                navbar.classList.remove('navbar--hide');
                navbar.classList.add('navbar--hide');
              }
              
              document.querySelector('.toc').querySelectorAll('a').forEach(function (elem) {
                elem.classList.remove('active');
              });
              elem.classList.add('active');

              var curElem = tableOfContentsElem.querySelector('[href="#' + id + '"]');
              if (curElem && curElem.nextElementSibling) {
                curElem.nextElementSibling.style.display = 'block';
              }
              if (curElem) {
                getParents(curElem, 'ul') ?
                  getParents(curElem, 'ul').forEach(function (elem) {
                    elem.style.display = 'block';
                  }) : null;
              }
            });
          });
        } else {
          if (tocFlexbox) {
            tocFlexbox.setAttribute('data-position', '');
            if (!tocFlexbox.classList.contains('hide')) {
              tocFlexbox.classList.add('hide');
            }
          }
          if (tocFlexboxOuter) {
            tocFlexboxOuter.setAttribute('data-position', '');
            if (!tocFlexboxOuter.classList.contains('hide')) {
              tocFlexboxOuter.classList.add('hide');
            }
          }
        }
      }

      
      var toggleTocElem = document.getElementById("toggle-toc");
      var visibleTocElem = document.getElementById('visible-toc');
      var tocElem = document.querySelector('.toc');
      var mainElem = document.querySelector('main');
      var sideElem = document.querySelector('side');
      var tocFlexboxElem = document.querySelector('.toc__flexbox');

      toggleTocElem ? 
      toggleTocElem.addEventListener('change', function(e) {
        if (e.target.checked) {
          if (tocElem) {
            fadeIn(tocElem, 200);
          }
          if (tocFlexboxElem) {
            tocFlexboxElem.setAttribute('data-position', 'fixed');
          }

          if (mainElem) {
            mainElem.classList.remove('main-main');
            mainElem.classList.remove('main');
            mainElem.classList.add('main-main');
          }
          if (sideElem) {
            sideElem.classList.remove('main-side');
          }
        } else {
          if (tocElem) {
            fadeOut(tocElem, 200);
          }
          if (tocFlexboxElem) {
            tocFlexboxElem.setAttribute('data-position', 'absolute');
          }

          if (mainElem) {
            mainElem.classList.remove('main-main');
            mainElem.classList.remove('main');
            mainElem.classList.add('main');
          }
          if (sideElem) {
            sideElem.classList.remove('main-side');
          }
        }
      }) : null;

      visibleTocElem ?
      visibleTocElem.addEventListener('change', function(e) {
        if (e.target.checked) {
          if (tocElem) {
            fadeIn(tocElem, 200);
          }
        } else {
          if (tocElem) {
            fadeOut(tocElem, 200);
          }
        }
      }) : null;
    }
    
    
    
    
    
    var topOffset = 120;
    var botOffset = 70;
    var handleWindowResize = function () {
      if (tocElem) {
        tocElem.style.maxHeight = (window.innerHeight - topOffset - botOffset) + 'px';
      }
    }
    var throttledWindowResize = throttle(handleWindowResize, 300);
    throttledWindowResize()

    
    window.addEventListener('resize', throttledWindowResize);
    



    
    var text, clip = new ClipboardJS('.anchor');
    var headers = singleContentsElem.querySelectorAll("h1, h2, h3, h4");

    
    var languagedir = JSON.parse("\"ltr\"");

    headers ? 
    headers.forEach(function (elem) {
      var size = parseInt(elem.tagName.substr(1), 10) * 2;
      var url = encodeURI(document.location.origin + document.location.pathname);
      var link = url + "#" + elem.getAttribute('id');
      var newElemOuter = document.createElement('span');
      newElemOuter.classList.add('anchor');
      newElemOuter.classList.add('hide');
      newElemOuter.setAttribute('data-clipboard-text', decodeURI(link));
      newElemOuter.style.position = 'relative';

      var newElemInner = document.createElement('span');
      newElemInner.style.position = 'absolute';
      newElemInner.style.top = '50%';
      newElemInner.style.left = '0.75rem';
      newElemInner.style.transform = 'translateY(-50%)';
      newElemInner.innerHTML = `
<svg fill="currentColor" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="${32 - size}px" height="${32 - size}px"><path d="M 5.5625 0 C 4.136719 0 2.707031 0.542969 1.625 1.625 C -0.539063 3.789063 -0.539063 7.335938 1.625 9.5 L 5.28125 13.15625 C 5.667969 13.554688 6.304688 13.558594 6.703125 13.171875 C 7.101563 12.785156 7.105469 12.148438 6.71875 11.75 L 3.03125 8.0625 C 1.632813 6.664063 1.632813 4.429688 3.03125 3.03125 C 4.429688 1.632813 6.664063 1.632813 8.0625 3.03125 L 12.96875 7.9375 C 14.367188 9.335938 14.367188 11.570313 12.96875 12.96875 C 12.804688 13.132813 12.621094 13.25 12.4375 13.375 C 11.980469 13.6875 11.859375 14.308594 12.171875 14.765625 C 12.484375 15.222656 13.105469 15.34375 13.5625 15.03125 C 13.847656 14.835938 14.125 14.625 14.375 14.375 C 16.539063 12.210938 16.539063 8.664063 14.375 6.5 L 9.5 1.625 C 8.417969 0.542969 6.988281 0 5.5625 0 Z M 10.78125 8.875 C 10.738281 8.882813 10.695313 8.894531 10.65625 8.90625 C 10.507813 8.9375 10.371094 9 10.25 9.09375 C 10.039063 9.253906 9.820313 9.429688 9.625 9.625 C 7.460938 11.789063 7.460938 15.335938 9.625 17.5 L 14.5 22.375 C 16.664063 24.539063 20.210938 24.539063 22.375 22.375 C 24.539063 20.210938 24.539063 16.664063 22.375 14.5 L 18.71875 10.875 C 18.476563 10.578125 18.089844 10.441406 17.714844 10.527344 C 17.34375 10.613281 17.050781 10.90625 16.964844 11.277344 C 16.878906 11.652344 17.015625 12.039063 17.3125 12.28125 L 20.96875 15.9375 C 22.367188 17.335938 22.367188 19.570313 20.96875 20.96875 C 19.570313 22.367188 17.335938 22.367188 15.9375 20.96875 L 11.03125 16.0625 C 9.632813 14.664063 9.632813 12.429688 11.03125 11.03125 C 11.152344 10.90625 11.300781 10.820313 11.4375 10.71875 C 11.839844 10.472656 12.015625 9.976563 11.855469 9.53125 C 11.699219 9.085938 11.25 8.8125 10.78125 8.875 Z"/></svg>`;

      if (languagedir === "rtl") {
        newElemInner.style.left = '-2rem';
      } else {
        newElemInner.style.right = '-2rem';
      }

      newElemOuter.append(newElemInner);
      elem.append(newElemOuter);

      elem.addEventListener('mouseenter', function() {
        this.querySelector('.anchor').classList.remove('hide');
      });
      elem.addEventListener('mouseleave', function () {
        this.querySelector('.anchor').classList.add('hide');
      });
    }) : null;

    document.querySelectorAll('.anchor').forEach(function(elem) {
      elem.addEventListener('mouseleave', function() {
        elem.setAttribute('aria-label', null);
        elem.classList.remove('tooltipped');
        elem.classList.remove('tooltipped-s');
        elem.classList.remove('tooltipped-w');
      });
    });

    clip.on('success', function (e) {
      e.clearSelection();
      e.trigger.setAttribute('aria-label', 'Link copied to clipboard!');
      e.trigger.classList.add('tooltipped');
      e.trigger.classList.add('tooltipped-s');
    });
    // =================================================================



    
    
    var lib = JSON.parse("[\"katex\"]");

    if (lib && lib.includes('mermaid')) {
      
      var themeVariant = localStorage.getItem('theme') || JSON.parse("\"dark\"");

      if (themeVariant === "dark" || themeVariant === "hacker") {
        mermaid.initialize({ theme: 'dark' });
      } else {
        mermaid.initialize({ theme: 'default' });
      }
      
      var mermaids = [];
      [].push.apply(mermaids, document.getElementsByClassName('language-mermaid'));
      mermaids.forEach(function(elem) {
        var elemParentNode = elem.parentNode;

        if (elemParentNode !== document.body) {
          elemParentNode.parentNode.insertBefore(elem, elemParentNode);
          elemParentNode.parentNode.removeChild(elemParentNode);
        }

        var newElemWrapper = document.createElement('div');
        newElemWrapper.classList.add('mermaid');
        newElemWrapper.style.padding = '34px 4px 6px';
        newElemWrapper.innerHTML = elem.innerHTML;
        elem.replaceWith(newElemWrapper);
      });
    }
    

    

    
    if (lib && lib.includes('katex')) {
      var mathElements = document.getElementsByClassName('math');
      var options = {
        delimiters: [
          { left: "$$", right: "$$", display: true },
          { left: "\\[", right: "\\]", display: true },
          { left: "$", right: "$", display: false },
          { left: "\\(", right: "\\)", display: false }
        ],
      };

      renderMathInElement(document.querySelector('.single__contents'), options);
    }
    



    
    if (lib && lib.includes('flowchartjs')) {
      
      var options = JSON.parse("{\"arrow-end\":\"block\",\"element-color\":\"black\",\"fill\":\"white\",\"flowstate\":{\"approved\":{\"fill\":\"#58C4A3\",\"font-size\":12,\"no-text\":\"n/a\",\"yes-text\":\"APPROVED\"},\"current\":{\"fill\":\"yellow\",\"font-color\":\"red\",\"font-weight\":\"bold\"},\"future\":{\"fill\":\"#FFFF99\"},\"invalid\":{\"fill\":\"#444444\"},\"past\":{\"fill\":\"#CCCCCC\",\"font-size\":12},\"rejected\":{\"fill\":\"#C45879\",\"font-size\":12,\"no-text\":\"REJECTED\",\"yes-text\":\"n/a\"},\"request\":{\"fill\":\"blue\"}},\"font-color\":\"black\",\"font-size\":14,\"line-color\":\"black\",\"line-length\":50,\"line-width\":3,\"no-text\":\"no\",\"scale\":1,\"symbols\":{\"end\":{\"class\":\"end-element\"},\"start\":{\"element-color\":\"green\",\"fill\":\"yellow\",\"font-color\":\"red\"}},\"text-margin\":10,\"x\":0,\"y\":0,\"yes-text\":\"yes\"}");
      var jsonContent = null;

      var flowchartPrefix = "language-flowchart";
      var index = 0;
      Array.prototype.forEach.call(document.querySelectorAll("[class^=" + flowchartPrefix + "]"), function(x){
          x.style.display = 'none'
          x.parentNode.style.backgroundColor = "transparent"
          jsonContent = x.innerText;

          var node0 = document.createElement('div');
          node0.id = 'flowchart' + index;
          x.parentNode.insertBefore(node0, x);

          var diagram = flowchart.parse(jsonContent);
          diagram.drawSVG("flowchart"+index, options);

          index +=1;
      });      
    }
    

    

    
    document.querySelectorAll("mjx-container").forEach(function (x) {
      x.parentElement.classList += 'has-jax'
    });
    



    
    if (lib && lib.includes('msc')) {
      
      var options = JSON.parse("{\"theme\":\"hand\"}");
      var jsonContent = null;

      var index = 0;
      var chartPrefix = "language-msc";
      Array.prototype.forEach.call(document.querySelectorAll("[class^=" + chartPrefix + "]"), function (x) {
        x.style.display = 'none'
        x.parentNode.style.backgroundColor = "transparent"
        jsonContent = x.innerText;
        var node0 = document.createElement('div');
        node0.id = 'msc' + index;
        x.parentNode.insertBefore(node0, x);
        var diagram = Diagram.parse(jsonContent);
        diagram.drawSVG("msc" + index, options);
        index += 1;
      });
    }
    



    
    if (lib && lib.includes('chart')) {
      var borderColor = "#666";
      var bgColor = "#ddd";
      var borderWidth = 2;

      Chart.defaults.global.elements.rectangle.borderWidth = borderWidth;
      Chart.defaults.global.elements.rectangle.borderColor = borderColor;
      Chart.defaults.global.elements.rectangle.backgroundColor = bgColor;

      Chart.defaults.global.elements.line.borderWidth = borderWidth;
      Chart.defaults.global.elements.line.borderColor = borderColor;
      Chart.defaults.global.elements.line.backgroundColor = bgColor;

      Chart.defaults.global.elements.point.borderWidth = borderWidth;
      Chart.defaults.global.elements.point.borderColor = borderColor;
      Chart.defaults.global.elements.point.backgroundColor = bgColor;

      var chartPrefix = "language-chart";
      var index = 0;
      var jsonContent = null;

      Array.prototype.forEach.call(document.querySelectorAll("[class^=" + chartPrefix + "]"), function (x) {
        x.style.display = 'none'
        x.parentNode.style.backgroundColor = "transparent"
        jsonContent = x.innerText;
        var node0 = document.createElement('canvas');
        var source = null;
        node0.height = 200;
        node0.style.height = 200;
        node0.id = 'myChart' + index;
        source = JSON.parse(jsonContent);
        x.parentNode.insertBefore(node0, x);
        var ctx = document.getElementById('myChart' + index).getContext('2d');
        var myChart = new Chart(ctx, source);
        index += 1;
      });            
    }
    



    
    if (lib && lib.includes('wavedrom')) {
      var wavePrefix = "language-wave";
      var index = 0;
      var jsonContent = null;
      
      Array.prototype.forEach.call(document.querySelectorAll("[class^=" + wavePrefix + "]"), function (x) {
        x.style.display = 'none'
        x.parentNode.style.backgroundColor = "transparent"
        jsonContent = x.innerText;
        var node0 = document.createElement('div');
        var source = null;
        node0.id = 'WaveDrom_Display_' + index;
        source = JSON.parse(jsonContent);
        x.parentNode.insertBefore(node0, x);
        WaveDrom.RenderWaveForm(index, source, "WaveDrom_Display_");
        index += 1;
      });
    }
    



    
    if (lib && lib.includes('viz')) {
      var vizPrefix = "language-viz-";
      Array.prototype.forEach.call(document.querySelectorAll("[class^=" + vizPrefix + "]"), function (x) {
        x.style.display = 'none'
        x.parentNode.style.backgroundColor = "transparent"
        var engine;
        x.getAttribute("class").split(" ").forEach(function (cls) {
          if (cls.startsWith(vizPrefix)) {
            engine = cls.substr(vizPrefix.length);
          }
        });
        var viz = new Viz();
        viz.renderSVGElement(x.innerText, { engine: engine })
          .then(function (element) {
            element.style.width = "100%";
            x.parentNode.insertBefore(element, x);
          })
      });
    }
    
    
  }
</script>


            
            <footer class="footer">
    
<div class="dropdown">
  <button class="dropdown-trigger" aria-label="Select Language Button">
    <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path fill="currentColor" d="M12.65 15.67c.14-.36.05-.77-.23-1.05l-2.09-2.06.03-.03c1.74-1.94 2.98-4.17 3.71-6.53h1.94c.54 0 .99-.45.99-.99v-.02c0-.54-.45-.99-.99-.99H10V3c0-.55-.45-1-1-1s-1 .45-1 1v1H1.99c-.54 0-.99.45-.99.99 0 .55.45.99.99.99h10.18C11.5 7.92 10.44 9.75 9 11.35c-.81-.89-1.49-1.86-2.06-2.88-.16-.29-.45-.47-.78-.47-.69 0-1.13.75-.79 1.35.63 1.13 1.4 2.21 2.3 3.21L3.3 16.87c-.4.39-.4 1.03 0 1.42.39.39 1.02.39 1.42 0L9 14l2.02 2.02c.51.51 1.38.32 1.63-.35zM17.5 10c-.6 0-1.14.37-1.35.94l-3.67 9.8c-.24.61.22 1.26.87 1.26.39 0 .74-.24.88-.61l.89-2.39h4.75l.9 2.39c.14.36.49.61.88.61.65 0 1.11-.65.88-1.26l-3.67-9.8c-.22-.57-.76-.94-1.36-.94zm-1.62 7l1.62-4.33L19.12 17h-3.24z"/></svg>
  </button>
  <div class="dropdown-content">
    
    
    
  </div>
</div>

    
    
<div id="gtt">
  <div class="gtt">
    <svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24"><path fill="currentColor" d="M8.12 14.71L12 10.83l3.88 3.88c.39.39 1.02.39 1.41 0 .39-.39.39-1.02 0-1.41L12.7 8.71c-.39-.39-1.02-.39-1.41 0L6.7 13.3c-.39.39-.39 1.02 0 1.41.39.38 1.03.39 1.42 0z"/></svg>
  </div>
</div>

    <hr />

    <div class="basicflex flexwrap">
        
            
        
            
        
    </div>

    <div class="footer__poweredby">
        
  <div class="busuanzi">
    
    
      <div class="busuanzi__item">
        <span class="busuanzi__item--label">
          Total visitors
        </span>
        <span id="busuanzi_value_site_uv" class="busuanzi__item--number">...</span>
      </div>
    

    
      <div class="busuanzi__item">
        <span class="busuanzi__item--label">
          Total views
        </span>
        <span id="busuanzi_value_site_pv" class="busuanzi__item--number">...</span>
      </div>
    

  </div>

                
            <p class="caption">
                
                    ©2023, All Rights Reserved
                
            </p>
        

        
        
    </div> 
</footer>
        </div>
        





<div class="wrapper__right hide" data-pad="true" dir="ltr">
  <script>document.querySelector('.wrapper__right').classList.remove('hide')</script>
  
</div>

    </div>
</body>

</html>